v3.0.0 was released on January 16, 2024. It moved the SDK to a new control plane API at api.pinecone.io, which ended the rigid one-to-one link between API keys and environments, and it was the first release that could create serverless indexes. Code written for 2.2.x fails on the first pinecone.init() call. This guide covers the v3 changes, which every later version builds on, and ends with what changed after v3 so you know where to go next. It follows Pinecone's release notes, READMEs and migration guides, linked at the end.
What changed
- The PyPI package is now
pinecone.pinecone-clientis deprecated and its last release, 6.0.0, only tells you to switch. pinecone.init(api_key=..., environment=...)is replaced bypc = Pinecone(api_key=...). There is no environment argument.create_indextakes aspec:ServerlessSpec(cloud, region)orPodSpec(environment, pod_type, ...). Pod settings such aspod_typeandreplicasmoved intoPodSpec.- Indexes are targeted with
pc.Index(host=...)(recommended) orpc.Index(name). list_indexes()returns full descriptions; chain.names()for the old list of names.describe_indexreturns a new shape, with settings underspecandhostat the top level.query()needs keyword arguments, and thequeriesbatch argument is gone.
Migration steps
Swap the package
pip uninstall pinecone-client pip install pineconeUninstall first. Pinecone warns that leaving
pinecone-clientinstalled next topineconecan lead to confusing interactions between the two, and its docs say upgrading under the old name stops working from v6.0.0. The import name stayspinecone. v3 itself still shipped aspinecone-client, so lock files pinned topinecone-client==3.xare already past this guide's code changes but not past the rename.Replace pinecone.init with a client
Before
import pinecone pinecone.init(api_key="YOUR_API_KEY", environment="us-west1-gcp") pinecone.describe_index("example-index")After
from pinecone import Pinecone pc = Pinecone(api_key="YOUR_API_KEY") # or Pinecone() to read PINECONE_API_KEY pc.describe_index("example-index")Control-plane functions that used to be module-level (
create_index,describe_index,delete_index,configure_index, the collection functions) are now methods on the client. Because configuration lives on the instance, one process can use several API keys. DeletePINECONE_ENVIRONMENTsettings that only existed forinit.Pass a spec to create_index
Before
pinecone.create_index("example-index", dimension=1536, metric="cosine")After
from pinecone import Pinecone, ServerlessSpec pc = Pinecone() pc.create_index( name="example-index", dimension=1536, metric="cosine", spec=ServerlessSpec(cloud="aws", region="us-west-2"), )In v3, pod indexes use
spec=PodSpec(environment="us-west-2", pod_type="p1.x1"), andmetadata_configandreplicasmove insidePodSpectoo. Index creation code is where later versions changed most, so read the callout in the last step before you write newPodSpeccalls.Target indexes by host
Before
index = pinecone.Index("example-index") index.upsert(vectors=[("vec1", [0.1, 0.2, 0.3, 0.4], {"genre": "drama"})])After
index = pc.Index(host=os.environ["INDEX_HOST"]) index.upsert(vectors=[("vec1", [0.1, 0.2, 0.3, 0.4], {"genre": "drama"})])Get the host once from
pc.describe_index("example-index").hostor the Pinecone console and store it in configuration.pc.Index("example-index")also works, but the client then makes an extra control-plane call to look up the host, which Pinecone does not recommend for production. As the example shows, theupsertcall itself keeps its shape.Chain .names() on list calls
Before
if "example-index" not in pinecone.list_indexes(): pinecone.create_index("example-index", dimension=1536)After
if "example-index" not in pc.list_indexes().names(): pc.create_index( name="example-index", dimension=1536, metric="cosine", spec=ServerlessSpec(cloud="aws", region="us-west-2"), )list_indexes()now returns anIndexListof full descriptions (name, dimension, metric, status, host, spec), andlist_collections()changed the same way. Without.names(), anincheck compares a name with description objects instead of names, so the code above can try to create an index that already exists. Code readingdescribe_index()results needs the same review: pod settings are underspec.Query with keyword arguments
Before
results = index.query([0.1, 0.2, 0.3, 0.4], top_k=10, include_metadata=True)After
results = index.query(vector=[0.1, 0.2, 0.3, 0.4], top_k=10, include_metadata=True)top_kbecame the first positional parameter, so passing the vector positionally produces a confusing API error about duplicatetop_kvalues. Thequeriesargument for several vectors in one call was removed; loop over your vectors instead. gRPC users import the client from the subpackage:from pinecone.grpc import PineconeGRPC.Know what changed after v3
If you install the latest
pinecone, the v3 call shapes above still run, but two later majors changed the canonical forms. v9 grouped control-plane calls under namespaces (pc.indexes.create,pc.indexes.list), madepc.index("name")lowercase, raised the minimum Python to 3.10, and kept the v3-style methods as shims so you can move gradually.
How to find every affected call
Every v2 control-plane call goes through the pinecone module, so ast-grep finds them reliably, including calls split across lines:
sg run --pattern 'pinecone.init($$$ARGS)' --lang python
sg run --pattern 'pinecone.Index($$$ARGS)' --lang python
sg run --pattern 'pinecone.create_index($$$ARGS)' --lang python
sg run --pattern 'pinecone.list_indexes()' --lang python
sg run --pattern 'pinecone.$METHOD($$$ARGS)' --lang python
sg run --pattern '$INDEX.query($VECTOR, $$$REST)' --lang pythonThe broad pinecone.$METHOD pattern catches the rest of the module-level calls (describe_index, configure_index, create_collection and so on). The last pattern finds queries whose first argument is positional; it can also match other libraries' query methods, so check each hit. Also check dependency files for pinecone-client, including transitive pins from other packages.
Testing the change
- Use a separate test project and API key, and create a small serverless index for the test run rather than pointing tests at production indexes.
- Replace mocks of
pinecone.initandpinecone.Indexwith a fakePineconeclient injected into your code; old mocks pass against code that no longer exists. - Test the paths that branch on
list_indexes(). The missing.names()bug does not raise, it just takes the wrong branch. - Set
PINECONE_DEBUG_CURL='true'while debugging to see the requests the client sends.
Automating it
We found no official codemod for this upgrade in Pinecone's release notes, READMEs or docs. The migration is a manual edit guided by the v3.0.0 migration guide, and later ones for v9 and v10.
Versyka finds the call sites deterministically with ast-grep patterns like the ones above, rewrites them along with the code that reads the results (the .names() checks, describe_index fields, mocks), then runs your repository's own tests in an isolated virtualenv inside a disposable sandbox. It opens a pull request only if they pass.
Was this guide helpful?
Check your own repository
Paste your package.json, requirements.txt or pyproject.toml into the free upgrade check to see which API SDKs are behind, with no account. Or let Versyka run this migration on one repository and open a pull request that has already passed your tests.
Sources
- Pinecone: pinecone-python-client v3.0.0 release notes
- Pinecone: pinecone-python-client v3.0.0 README
- Pinecone: pinecone-python-client v2.2.4 README
- Pinecone: Python SDK documentation
- Pinecone: Migrating from v8.x to v9.x
- Pinecone: Migrating to V10
- PyPI: pinecone-client (deprecated)
- ast-grep: pattern syntax