# Agentic IDEs and CLIs
Source: https://docs.pinecone.io/guides/get-started/ai-coding-tools
Use Pinecone with agentic IDEs and CLIs like Claude Code, Gemini CLI, and Cursor via MCP server, plugins, and agent skills for vector search.
Pinecone provides official plugins, extensions, and agent skills for agentic IDEs and CLIs. Use the Pinecone [MCP server](/guides/operations/mcp-server) (Model Context Protocol) and built-in skills to manage vector database indexes, run semantic search, and build RAG applications — all through natural language in your development environment. For direct, scriptable access from the same terminal, the [Pinecone CLI](/reference/cli/quickstart) (`pc`) lets you manage indexes, namespaces, and records without an agent in the loop.
## Choose your tool
Official Pinecone plugin for Claude Code with skills, MCP tools, and slash commands.
Official Pinecone extension for Gemini CLI with skills and MCP tools.
Official Pinecone plugin for Cursor with skills, MCP tools, and slash commands.
Universal skills library for GitHub Copilot, Codex, and other agentic IDEs.
Connect any MCP-compatible client to Pinecone for index management and search.
Direct terminal access to Pinecone — manage indexes, namespaces, and records with `pc` commands.
## Which tool should I use?
| If you use... | Install... | Command |
| ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------------------------- |
| [Claude Code](https://claude.ai/code) | [Pinecone plugin for Claude Code](/integrations/claude-code) | `claude plugin install pinecone` |
| [Gemini CLI](https://github.com/google-gemini/gemini-cli) | [Pinecone Gemini CLI extension](/integrations/gemini-cli) | `gemini extensions install https://github.com/pinecone-io/gemini-cli-extension` |
| [Cursor](https://www.cursor.com/) | [Pinecone Cursor plugin](/integrations/cursor) | `/add-plugin pinecone` |
| [GitHub Copilot](https://github.com/features/copilot), [Codex](https://chatgpt.com/codex), or another agentic IDE | [Pinecone Agent Skills](/integrations/agent-skills) | `npx skills add pinecone-io/skills` |
| Claude Desktop, Antigravity, or another MCP client | [Pinecone MCP server](/guides/operations/mcp-server) | See [MCP server setup](/guides/operations/mcp-server) |
| Your terminal directly (no agent) | [Pinecone CLI](/reference/cli/quickstart) | `brew install pinecone-io/tap/pinecone` |
All tools require a [Pinecone API key](https://app.pinecone.io/organizations/-/keys). Sign up for a free account at [app.pinecone.io](https://app.pinecone.io).
## What's included
Each tool provides access to the following Pinecone skills:
| Skill | Description |
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **quickstart** | Step-by-step onboarding — create an index, upload data, and run your first search. |
| **query** | Search integrated indexes using natural language text via the Pinecone MCP. |
| **assistant** | Create, manage, and chat with Pinecone Assistants for document Q\&A with citations. |
| **cli** | Use the Pinecone CLI for terminal-based index and vector management. |
| **full-text-search** | Create, ingest into, and query a Pinecone full-text-search (FTS) index using the preview API. |
| **n8n** | Build [n8n](/integrations/n8n) workflows with the Pinecone Assistant node or Pinecone Vector Store, including best practices and full workflow JSON generation. |
| **mcp** | Reference for all available Pinecone MCP server tools and their parameters. |
| **pinecone-docs** | Curated links to official Pinecone documentation, organized by topic. |
| **help** | Overview of all skills and what you need to get started. |
In addition, the [Pinecone MCP server](/guides/operations/mcp-server) provides tools for listing indexes, creating indexes, upserting records, searching, reranking, and more.
# Concepts
Source: https://docs.pinecone.io/guides/get-started/concepts
Learn core Pinecone concepts (organizations, projects, indexes, documents, namespaces, dense and sparse vectors) and how they relate.
## Organization
An organization is a group of one or more [projects](#project) that use the same billing. Organizations allow one or more [users](#user) to control billing and permissions for all of the projects belonging to the organization.
For more information, see [Understanding organizations](/guides/organizations/understanding-organizations).
## Project
A project belongs to an [organization](#organization) and contains one or more [indexes](#index). Each project belongs to exactly one organization, but only [users](#user) who belong to the project can access the indexes in that project. [API keys](#api-key) and [Assistants](#assistant) are project-specific.
For more information, see [Understanding projects](/guides/projects/understanding-projects).
## Index
Pinecone [serverless indexes](/guides/index-data/indexing-overview) hold your data as [documents](#document) or [records](#record), depending on how the index was created: an index created with a document schema holds documents, while an index created with a dense or sparse vector type holds records. A document is a JSON object with ranking fields that Pinecone indexes according to a schema you define, plus any number of metadata fields. A single index with a document schema can mix multiple ranking field types: a `dense_vector` field for [semantic search](#index-with-dense-vectors), a `sparse_vector` field for [sparse-vector retrieval](#index-with-sparse-vectors), and one or more `string` fields with `full_text_search` enabled for [full-text search](#full-text-search) with BM25 and Lucene queries. Metadata fields (anything else you upsert) are auto-indexed for filtering at upsert time, no schema declaration required.
One index per use case is the typical pattern. Because a document can combine vectors, text, and metadata in the same record, a single index often covers what previously required two — pick the ranking signal per query with `score_by`.
### Full-text search
Full-text search is **BM25 token matching with Lucene query syntax** over text fields in your schema — `string` fields you've declared with `full_text_search` so their content is indexed for token-level retrieval. "Text field" is the colloquial name; the JSON `type` is `string`. No model required — Pinecone handles tokenization, IDF, and length normalization at index time and BM25 scoring at query time. "Token" here means a unit produced by Pinecone's text analyzer (whitespace + punctuation split, lowercased, optionally stemmed) — not the subword unit a dense or sparse embedding model uses internally. See [Tokens and analyzers](/guides/search/full-text-search#tokens-and-analyzers) for the full pipeline.
How it works:
1. You upsert data as JSON [documents](#document).
2. You declare each ranking field's type in the index schema: `dense_vector`, `sparse_vector`, or `string` with `full_text_search` (indexed for BM25 ranking and Lucene queries). Metadata fields are not declared in the schema.
3. Pinecone indexes each ranking field according to its declared type and auto-indexes any other fields on the document for metadata filtering.
When you search, you choose a scoring method via `score_by`. The literal value of `type` selects the method: `text` (BM25 token matching on a single text field), `query_string` ([Lucene query syntax](/guides/search/full-text-search#query-syntax-reference) across one or more text fields, including cross-field boolean queries), `dense_vector` (vector similarity), or `sparse_vector` (sparse-vector similarity). Any scoring method can be combined with metadata filters — including logical operators (`$and`, `$or`, `$not`), existence checks (`$exists`), and the text-match operators (`$match_phrase`, `$match_all`, `$match_any`) for phrase and token matching against text fields.
Use full-text search for keyword and phrase search over text content — product names, identifiers, technical terms, code, and other cases where queries and documents share specific tokens. For sparse-vector retrieval with a learned encoder (such as [`pinecone-sparse-english-v0`](/models/pinecone-sparse-english-v0)), see [Index with sparse vectors](#index-with-sparse-vectors). For semantic similarity over natural-language queries, see [Index with dense vectors](#index-with-dense-vectors).
Learn more:
* [Full-text search](/guides/search/full-text-search)
* [Document](#document)
### Index with dense vectors
These indexes store records that each have one [dense vector](#dense-vector). A dense vector is a series of numbers that represent the meaning and relationships of text, images, or other data. Each vector is a point in a multidimensional space; each number is a coordinate in that space. Vectors that are closer together in that space are semantically similar.
When you query an index with dense vectors, Pinecone retrieves records whose vectors are most semantically similar to the query. This is often called **semantic search**, nearest neighbor search, similarity search, or just vector search.
If records in an index with dense vectors also have a [sparse vector](#sparse-vector), the index supports single-index [hybrid search](/guides/search/hybrid-search#use-a-single-index-for-dense-and-sparse-vectors) on the same records. This single-index pattern uses the vector API and isn't available for indexes with document schemas. To combine a lexical signal with a dense signal in an index with a document schema, restrict a dense search with a text-match filter or run separate searches and merge the results client-side; see [Hybrid search](/guides/search/hybrid-search).
### Index with sparse vectors
These indexes store records that each have one [sparse vector](#sparse-vector) — a vector with very high dimensionality but only a small number of non-zero values. Each dimension typically corresponds to a token in a vocabulary; the non-zero values represent the importance of those tokens in a document.
When you search an index with sparse vectors, Pinecone retrieves records whose vectors share the most weighted tokens with the query vector. This is often called **sparse-vector retrieval** or **sparse-vector lexical search**.
Sparse vectors are produced by a sparse embedding model. Pinecone hosts [`pinecone-sparse-english-v0`](/models/pinecone-sparse-english-v0), a learned-sparse encoder that predicts per-token weights and includes term expansion (related concepts that don't appear in the source text). You can also bring your own sparse model.
**Sparse-vector lexical search vs. full-text search.** Both retrieve documents using token-level signals over an inverted index. They differ in how tokens are weighted: [full-text search](#full-text-search) uses **BM25** — a statistical scoring function with no machine learning, computed at query time over your raw text fields. Sparse-vector lexical search uses a **learned sparse encoder** that produces token weights at index time, often with term expansion. Use full-text search when you want a strong baseline with no model to manage; use sparse vectors when a learned encoder (yours or Pinecone's hosted one) better captures your domain's term importance and synonyms.
A useful gradient: dense ranks on **concept** (semantic similarity), full-text search ranks on **strict character-level token matching** (BM25), and sparse-vector lexical search sits **between them** — token-aware, but with learned per-token weights and term expansion. Sparse vectors carry no positional information, so phrase matching (`"machine learning"` as a contiguous span) requires full-text search, not sparse.
## Namespace
A namespace is a partition within an index. It divides [records](#record) into separate groups so that each query scans only one namespace (faster lookups) and each customer's data can be isolated from another customer's (multitenant isolation).
All [upserts](/guides/index-data/upsert-data), [queries](/guides/search/search-overview), and other data read and write operations always target one namespace:
For more information, see [Use namespaces](/guides/index-data/indexing-overview#namespaces).
## Record
A record is the unit of data for [indexes with dense vectors](#index-with-dense-vectors) and [indexes with sparse vectors](#index-with-sparse-vectors): a [record ID](#record-id), one vector (or both vector types for single-index [hybrid search](/guides/search/hybrid-search)), and optional [metadata](#metadata). With [integrated embedding](/guides/index-data/indexing-overview#integrated-embedding) you can upsert raw text instead of a vector, and Pinecone embeds it at index time. When an item has more than one searchable field — say, a text field ranked by BM25 alongside a `dense_vector` field for similarity — model it as a [document](#document).
For more information, see [Upsert data](/guides/index-data/upsert-data).
## Document
A document is the unit of data in an index with a document schema — a JSON object with a required `_id` field, the ranking fields declared in the index's schema, and any number of metadata fields. Documents support multiple ranking field types in a single record: a `dense_vector` field (for [semantic search](#index-with-dense-vectors)), a `sparse_vector` field (for [sparse-vector retrieval](#index-with-sparse-vectors)), and one or more `string` fields with `full_text_search` enabled (for [full-text search](#full-text-search)). A single document can carry vectors, text, and metadata together, and you choose the scoring method per query via `score_by`. Documents are the recommended shape for new multi-field and full-text workloads; vector-only indexes continue to use [records](#record). Both APIs are fully supported.
Document fields can hold structured values: a metadata `string_list` field holds an array of strings; a `dense_vector` field holds an array of floats; a `sparse_vector` field is an object with two parallel arrays — `indices` (token positions) and `values` (token weights).
A schema can declare up to 100 `string` fields with `full_text_search` enabled, but at most one `dense_vector` field and at most one `sparse_vector` field per index.
Metadata fields are not declared in the schema. Any field on an upserted document that is not declared in the schema is stored, returned via `include_fields`, and automatically indexed for filtering. Pinecone infers metadata field types (string, number, boolean, array of strings) from the values you upsert.
Field names must be unique, non-empty strings, must not start with `_` (reserved for system-managed fields like `_id` and `_score`) or `$` (reserved for filter operators), and are limited to 64 bytes.
For more information, see [Full-text search](/guides/search/full-text-search).
### Record ID
A record ID is a record's unique ID. [Use ID prefixes](/guides/index-data/data-modeling#use-structured-ids) that reflect the type of data you're storing.
### Dense vector
A dense vector, also referred to as a vector embedding or simply a vector, is a series of numbers that represent the meaning and relationships of data. Each vector is a point in a multidimensional space; each number is a coordinate in that space. Vectors that are closer together in that space are semantically similar.
Dense vectors are stored in indexes (see [Index with dense vectors](#index-with-dense-vectors)).
You use a dense embedding model to convert data to dense vectors. The embedding model can be external to Pinecone or [hosted on Pinecone infrastructure](/guides/index-data/create-an-index#embedding-models) and integrated with an index.
For more information about dense vectors, see [What are vector embeddings?](https://www.pinecone.io/learn/vector-embeddings/).
### Sparse vector
Sparse vectors are often used to represent documents or queries in a way that captures keyword information. Each dimension in a sparse vector typically represents a word from a dictionary, and the non-zero values represent the importance of these words in the document.
Sparse vectors have a large number of dimensions, but a small number of those values are non-zero. Because most values are zero, Pinecone stores sparse vectors efficiently by keeping only the non-zero values along with their corresponding indices.
Sparse vectors are stored in indexes (see [Index with sparse vectors](#index-with-sparse-vectors)) and can also coexist with dense vectors in a single index for [hybrid search](/guides/search/hybrid-search#use-a-single-index-for-dense-and-sparse-vectors) on the vector API. To combine a lexical signal with a dense signal in an index with a document schema, restrict a dense search with a text-match filter on a `string` field with `full_text_search` enabled or run separate searches and merge the results client-side. To convert data to sparse vectors, use a sparse embedding model. The embedding model can be external to Pinecone or [hosted on Pinecone infrastructure](/guides/index-data/create-an-index#embedding-models) and integrated with an index.
For more information about sparse vectors, see [Sparse retrieval](https://www.pinecone.io/learn/sparse-retrieval/).
### Metadata
Metadata is additional information included in a record to provide more context and enable additional [filtering capabilities](/guides/index-data/indexing-overview#metadata). For example, the original text that was embedded can be stored in the metadata.
## Other concepts
Although not represented in the diagram above, Pinecone also contains the following concepts:
* [API key](#api-key)
* [User](#user)
* [Backup or collection](#backup-or-collection)
* [Pinecone Inference](#pinecone-inference)
* [Read unit (RU)](#read-unit-ru)
* [Write unit (WU)](#write-unit-wu)
### API key
An API key is a unique token that [authenticates](/reference/api/authentication) and authorizes access to the [Pinecone APIs](/reference/api/introduction). API keys are project-specific.
### User
A user is a member of organizations and projects. Users are assigned specific roles at the organization and project levels that determine the user's permissions in the [Pinecone console](https://app.pinecone.io).
For more information, see [Manage organization members](/guides/organizations/manage-organization-members) and [Manage project members](/guides/projects/manage-project-members).
### Backup or collection
A backup is a static copy of a serverless index.
Backups only consume storage. They are non-queryable representations of a set of records. You can create a backup from an index, and you can create a new index from that backup. The new index configuration can differ from the original source index: for example, it can have a different name. However, it must have the same number of dimensions and similarity metric as the source index.
For more information, see [Understanding backups](/guides/manage-data/backups-overview).
### Pinecone Inference
Pinecone Inference is an API service that provides access to [embedding models](/guides/index-data/create-an-index#embedding-models) and [reranking models](/guides/search/rerank-results#reranking-models) hosted on Pinecone's infrastructure.
### Read unit (RU)
A read unit (RU) is the unit Pinecone uses to measure and price the cost of read requests to a serverless index, including [query](/guides/manage-cost/understanding-cost#query), [fetch](/guides/manage-cost/understanding-cost#fetch), and [list](/guides/manage-cost/understanding-cost#list).
For how read units are calculated, see [Understanding cost](/guides/manage-cost/understanding-cost#read-units).
### Write unit (WU)
A write unit (WU) is the unit Pinecone uses to measure and price the cost of write requests to a serverless index, including [upsert](/guides/manage-cost/understanding-cost#upsert), [update](/guides/manage-cost/understanding-cost#update), and [delete](/guides/manage-cost/understanding-cost#delete).
For how write units are calculated, see [Understanding cost](/guides/manage-cost/understanding-cost#write-units).
## Learn more
* [Vector database](https://www.pinecone.io/learn/vector-database/)
* [Pinecone APIs](/reference/api/introduction)
* [Approximate nearest neighbor (ANN) algorithms](https://www.pinecone.io/learn/a-developers-guide-to-ann-algorithms/)
* [Retrieval augmented generation (RAG)](https://www.pinecone.io/learn/retrieval-augmented-generation/)
* [Image search](https://www.pinecone.io/learn/series/image-search/)
* [Tokenization](https://www.pinecone.io/learn/tokenization/)
# Architecture
Source: https://docs.pinecone.io/guides/get-started/database-architecture
Learn how Pinecone's serverless architecture (API gateway, control plane, data plane, and object storage) powers vector search at scale.
## Overview
Pinecone runs as a managed service on AWS, GCP, and Azure cloud platforms. When you send a request to Pinecone, it goes through an [API gateway](#api-gateway) that routes it to either a global [control plane](#control-plane) or a regional [data plane](#data-plane). All your vector data is stored in highly efficient, distributed [object storage](#object-storage).
### API gateway
Every request to Pinecone includes an [API key](/guides/projects/manage-api-keys) that's assigned to a specific [project](/guides/projects/understanding-projects). The API gateway first validates your API key to make sure you have permission to access the project. Once validated, it routes your request to either the global control plane (for managing projects and indexes) or a regional data plane (for reading and writing data), depending on what you're trying to do.
### Control plane
The global control plane manages your organizational resources like projects and indexes. It uses a dedicated database to keep track of all these objects. The control plane also handles billing, user management, and coordinates operations across different regions.
### Data plane
The data plane handles all requests to write and read records in [indexes](/guides/index-data/indexing-overview) within a specific [cloud region](/guides/index-data/create-an-index#cloud-regions). Each index is divided into one or more logical [namespaces](/guides/index-data/indexing-overview#namespaces), and all your data read and write requests target a specific namespace.
Pinecone separates write and read operations into different paths, with each scaling independently based on demand. This separation ensures that your queries never slow down your writes, and your writes never slow down your queries.
### Object storage
For each namespace in a serverless index, Pinecone organizes records into immutable files called slabs. These slabs are [optimized for fast querying](#index-builder) and stored in distributed object storage that provides virtually unlimited scalability and high availability.
## Write path
### Request log
When you send a write request (to add, update, or delete records), the [data plane](#data-plane) first logs the request details with a unique sequence number (LSN). This ensures all operations happen in the correct order and provides a way to track the state of the index.
Pinecone immediately returns a `200 OK` response, guaranteeing that your write is durable and won't be lost. The system then processes your write in the background.
### Index builder
The index builder stores your write data in an in-memory structure called a memtable. This includes your vector data, any metadata you've attached, and the sequence number. If you're updating or deleting a record, the system also tracks how to handle the old version during queries.
Periodically, the index builder moves data from the memtable to permanent storage. In [object storage](#object-storage), your data is organized into immutable files called slabs. These slabs are optimized for query performance. Smaller slabs use fast indexing techniques that provide good performance with minimal resource requirements. As slabs grow, the system merges them into larger slabs that use more sophisticated methods that provide better performance at scale. This adaptive process both optimizes query performance for each slab and amortizes the cost of more expensive indexing through the lifetime of the namespace.
All read operations check the memtable first, so you can immediately search data that you've just written, even before it's moved to permanent storage. For more details, see [Query executors](#query-executors).
## Read path
### Query routers
When you send a search query, the [data plane](#data-plane) first validates your request and checks that it meets system limits like [rate and object limits](/reference/api/database-limits). The query router then identifies which slabs contain relevant data and routes your query to the appropriate executors. It also searches the memtable for any recent data that hasn't been moved to permanent storage yet.
### Query executors
Each query executor searches through its assigned slabs and returns the most relevant candidates to the query router. If your query includes metadata filters, the executors exclude records that don't match your criteria before finding the best matches.
Most of the time, the slabs are cached in memory or on local SSD, which provides very fast query performance. If a slab isn't cached (which happens when it's accessed for the first time or hasn't been used recently), the executor fetches it from object storage and caches it for future queries.
The query router then combines results from all executors, removes duplicates, merges them with results from the memtable, and returns the final set of best matches to you.
# Pinecone documentation
Source: https://docs.pinecone.io/guides/get-started/overview
Pinecone is the vector database for AI agents and applications, built for semantic search, knowledge retrieval, and long-term memory at scale.
## Get started
Build semantic search and knowledge retrieval into your agent or app
Create an AI assistant that answers questions about your proprietary data
Compile your data into a context and query it for grounded, cited answers
Publish a no-code knowledge app from a template (public preview)
## Build
Use Pinecone with Claude Code, Gemini CLI, Cursor, and other agentic tools
Connect any MCP-compatible agent to Pinecone for search and index management
Comprehensive details about the Pinecone APIs, SDKs, and architecture
Notebooks and sample apps with common AI patterns
Third-party integrations for LangChain, LlamaIndex, and more
What's new in Pinecone
# Quickstart
Source: https://docs.pinecone.io/guides/get-started/quickstart
Add Pinecone to your AI agent or app in minutes. Build a knowledge retrieval agent, use your IDE assistant, or integrate the SDK directly.
Get Pinecone running in your agent or app. Install the Pinecone plugin for your AI coding tool to get started instantly, or follow a step-by-step path below.
## Agent / LLM? Start here
If you're an AI agent or LLM reading this page to generate Pinecone code, here's the full working pattern as a single runnable script.
```python theme={null}
import time
from pinecone import Pinecone
pc = Pinecone(api_key="{{YOUR_API_KEY}}")
# Use create_index_for_model, not the dimension-based create_index
if not pc.has_index("quickstart"):
pc.create_index_for_model(
name="quickstart",
cloud="aws",
region="us-east-1",
embed={
"model": "llama-text-embed-v2",
"field_map": {"text": "content"}
}
)
index = pc.Index("quickstart")
# Use upsert_records, not upsert(); keyword args required in SDK v9+; each record needs _id + the field_map field
index.upsert_records(
namespace="docs",
records=[
{"_id": "rec1", "content": "Refund requests must be submitted within 30 days.", "category": "policy"},
{"_id": "rec2", "content": "Enterprise support responds within 4 hours.", "category": "policy"},
{"_id": "rec3", "content": "New employees receive 15 days PTO in year one.", "category": "hr"},
{"_id": "rec4", "content": "Production deployments require team lead approval.", "category": "ops"},
{"_id": "rec5", "content": "API rate limit: 1000 requests/minute on Pro tier.", "category": "specs"},
]
)
time.sleep(5) # records take a few seconds to become searchable
# Use search() with inputs, not query() with vector=
results = index.search(
namespace="docs",
query={"top_k": 5, "inputs": {"text": "what is the refund policy"}},
rerank={
"model": "bge-reranker-v2-m3",
"top_n": 3,
"rank_fields": ["content"]
}
)
for hit in results["result"]["hits"]:
print(f"{hit.score:.2f} {hit.fields['content']}")
```
***
## Get set up
To get started, you'll need a Pinecone account and API key.
### 1. Create a Pinecone account
If you're new to Pinecone, sign up at [app.pinecone.io](https://app.pinecone.io) and choose a plan:
* [Starter plan](https://pinecone.io/pricing/) (free): Free access to most features, but you're limited to one cloud region and need to stay under Starter plan [limits](/reference/api/database-limits).
* [Builder plan](https://pinecone.io/pricing/) (\$20/month): Higher quotas than Starter and predictable flat pricing with no usage overages, plus the ability to create indexes in any supported cloud region. Ideal for small production apps.
* [Standard plan trial](/guides/organizations/manage-billing/standard-trial): 21 days and \$300 in credits with access to Standard plan [features](https://www.pinecone.io/pricing/) and [higher limits](/reference/api/database-limits) that let you test Pinecone at scale.
If you're already on a Starter plan, you can [upgrade to Builder](/guides/organizations/manage-billing/upgrade-billing-plan) at any time, or activate a Standard plan trial (one trial per organization).
After signing up, you'll receive an API key in the console. Save this key. You'll need it to authenticate your requests to Pinecone.
### 2. Get a Pinecone API key
Create a new API key in the [Pinecone console](https://app.pinecone.io/organizations/-/keys), or use the widget below to generate a key. If you don't have a Pinecone account, the widget will sign you up for the free [Starter plan](https://www.pinecone.io/pricing/).
Your generated API key:
```shell theme={null}
"{{YOUR_API_KEY}}"
```
## Fastest: use your AI coding tool
Install the Pinecone plugin for your AI coding tool, then run the quickstart command. The plugin gives your agent up-to-date Pinecone API references, skills, and a bundled MCP server. The quickstart command walks you through setup with the official [Pinecone CLI](/reference/cli/quickstart) before generating and running sample code, so you end up with a reproducible setup instead of pasted snippets.
Set your API key, then install the [Pinecone plugin for Claude Code](/integrations/claude-code):
```shell theme={null}
export PINECONE_API_KEY="{{YOUR_API_KEY}}"
claude plugin install pinecone
```
Start Claude Code and run the quickstart command:
```text theme={null}
/pinecone:quickstart
```
The plugin also includes other slash commands, such as `/pinecone:query`, for interactively querying your indexes.
Add your Pinecone API key to a `.env` file at your workspace root:
```text theme={null}
PINECONE_API_KEY={{YOUR_API_KEY}}
```
Install the [Pinecone plugin for Cursor](/integrations/cursor) from the [Cursor Marketplace](https://cursor.com/marketplace/pinecone), or in Cursor chat run:
```text theme={null}
/add-plugin pinecone
```
Then run the quickstart command in Cursor Agent chat:
```text theme={null}
/pinecone-quickstart
```
Install [Pinecone Agent Skills](/integrations/agent-skills), then ask your agent to get started:
```bash theme={null}
npx skills add pinecone-io/skills
```
```text theme={null}
Help me get started with Pinecone. Create a serverless index with
integrated embedding, upsert some sample data, and run a search.
```
To drive the same setup yourself without an AI tool, use the [Pinecone CLI](/reference/cli/quickstart) directly. For full MCP server setup (index management, search, and docs access from your IDE), see [Use the Pinecone MCP server](/guides/operations/mcp-server).
## Choose your path
**Records or documents?** There are two ways to model data in Pinecone, and the choice is made when you create the index. An index created with a dense or sparse vector type holds [records](/guides/get-started/concepts#record), the path the steps below follow using integrated embedding (`create_index_for_model` + `upsert_records` + `search`). An index created with a document schema holds [documents](/guides/get-started/concepts#document) and supports [full-text search](/guides/search/full-text-search) with BM25 ranking and Lucene queries (public preview, with REST and Python SDK support). If keyword and phrase matching matters to your search, or you need more than one ranking signal in a single index, start from [full-text search](/guides/search/full-text-search) instead. To compare the two models, see [Data modeling](/guides/index-data/data-modeling).
Build a knowledge retrieval agent with Pinecone as a tool. \~80 lines of Python.
Let Claude Code, Cursor, or Gemini CLI build it for you.
Integrate Pinecone directly with Python, JavaScript, Java, or Go.
Build a workflow in n8n without writing code.
***
## Build a knowledge retrieval agent
Build an AI agent that uses Pinecone to retrieve knowledge and answer questions accurately. This demo shows Pinecone as a tool inside an agent, which is the same pattern you'd use in production.
This path requires an [Anthropic](https://console.anthropic.com/) or [OpenAI](https://platform.openai.com/api-keys) API key alongside your Pinecone API key. If you don't have one, try the [IDE assistant](#fastest-use-your-ai-coding-tool) or [SDK](#integrate-the-sdk-directly) path instead.
```bash Anthropic (Claude) theme={null}
pip install pinecone anthropic
```
```bash OpenAI theme={null}
pip install pinecone openai
```
Create a Pinecone index with [integrated embedding](/guides/index-data/indexing-overview#integrated-embedding) and load a small knowledge base. These are facts your LLM doesn't know on its own, so retrieval is the only way to answer accurately.
```python Anthropic (Claude) theme={null}
import anthropic
from pinecone import Pinecone
pc = Pinecone(api_key="{{YOUR_API_KEY}}")
llm = anthropic.Anthropic(api_key="YOUR_ANTHROPIC_API_KEY")
# Create an index with integrated embedding
if not pc.has_index("knowledge"):
pc.create_index_for_model(
name="knowledge",
cloud="aws",
region="us-east-1",
embed={
"model": "llama-text-embed-v2",
"field_map": {"text": "content"}
}
)
index = pc.Index("knowledge")
# Load your knowledge base
index.upsert_records(
namespace="docs",
records=[
{"_id": "policy-1", "content": "Refund requests must be submitted within 30 days of purchase. After 30 days, only store credit is available.", "category": "policies"},
{"_id": "policy-2", "content": "Enterprise customers get dedicated support with a 4-hour response time SLA. Standard support responds within 24 hours.", "category": "policies"},
{"_id": "spec-1", "content": "The WonderVector 5000 supports up to 100,000 vectors per namespace with a maximum dimensionality of 4096.", "category": "specs"},
{"_id": "spec-2", "content": "API rate limits: Free tier is 100 requests/minute, Pro tier is 1000 requests/minute, Enterprise is unlimited with fair use.", "category": "specs"},
{"_id": "spec-3", "content": "Data is encrypted at rest using AES-256 and in transit using TLS 1.3. SOC2 Type II compliance is maintained.", "category": "security"},
{"_id": "hr-1", "content": "New employees receive 15 days PTO in their first year, increasing to 20 days after 2 years and 25 days after 5 years.", "category": "hr"},
{"_id": "hr-2", "content": "The company matches 401k contributions up to 4% of salary. Vesting is immediate for all employees.", "category": "hr"},
{"_id": "proc-1", "content": "To request a new software license, submit a ticket in the IT portal. Approvals take 2-3 business days for standard software.", "category": "procedures"},
{"_id": "proc-2", "content": "Production deployments require approval from the team lead and a passing CI/CD pipeline. Hotfixes can bypass the lead approval.", "category": "procedures"},
{"_id": "proc-3", "content": "Vendor invoices over $10,000 require VP approval. Under $10,000 requires manager approval only.", "category": "procedures"},
]
)
```
```python OpenAI theme={null}
from openai import OpenAI
from pinecone import Pinecone
pc = Pinecone(api_key="{{YOUR_API_KEY}}")
llm = OpenAI(api_key="YOUR_OPENAI_API_KEY")
# Create an index with integrated embedding
if not pc.has_index("knowledge"):
pc.create_index_for_model(
name="knowledge",
cloud="aws",
region="us-east-1",
embed={
"model": "llama-text-embed-v2",
"field_map": {"text": "content"}
}
)
index = pc.Index("knowledge")
# Load your knowledge base
index.upsert_records(
namespace="docs",
records=[
{"_id": "policy-1", "content": "Refund requests must be submitted within 30 days of purchase. After 30 days, only store credit is available.", "category": "policies"},
{"_id": "policy-2", "content": "Enterprise customers get dedicated support with a 4-hour response time SLA. Standard support responds within 24 hours.", "category": "policies"},
{"_id": "spec-1", "content": "The WonderVector 5000 supports up to 100,000 vectors per namespace with a maximum dimensionality of 4096.", "category": "specs"},
{"_id": "spec-2", "content": "API rate limits: Free tier is 100 requests/minute, Pro tier is 1000 requests/minute, Enterprise is unlimited with fair use.", "category": "specs"},
{"_id": "spec-3", "content": "Data is encrypted at rest using AES-256 and in transit using TLS 1.3. SOC2 Type II compliance is maintained.", "category": "security"},
{"_id": "hr-1", "content": "New employees receive 15 days PTO in their first year, increasing to 20 days after 2 years and 25 days after 5 years.", "category": "hr"},
{"_id": "hr-2", "content": "The company matches 401k contributions up to 4% of salary. Vesting is immediate for all employees.", "category": "hr"},
{"_id": "proc-1", "content": "To request a new software license, submit a ticket in the IT portal. Approvals take 2-3 business days for standard software.", "category": "procedures"},
{"_id": "proc-2", "content": "Production deployments require approval from the team lead and a passing CI/CD pipeline. Hotfixes can bypass the lead approval.", "category": "procedures"},
{"_id": "proc-3", "content": "Vendor invoices over $10,000 require VP approval. Under $10,000 requires manager approval only.", "category": "procedures"},
]
)
```
Pinecone is eventually consistent. New records may take a few seconds to become searchable.
Wrap Pinecone search in a function your agent can call. Drop this into any agent codebase to add knowledge retrieval. Run all snippets in the same Python session so `index` and `llm` stay in scope.
**Agent tool: `search_knowledge_base`**
```python Python theme={null}
def search_knowledge_base(query: str) -> str:
"""Search the knowledge base for relevant information."""
results = index.search(
namespace="docs",
# To scope by metadata, add "filter": {"category": {"$eq": "policies"}} to the query dict
query={"top_k": 3, "inputs": {"text": query}},
rerank={
"model": "bge-reranker-v2-m3",
"top_n": 3,
"rank_fields": ["content"]
}
)
return "\n\n".join(
hit.fields["content"]
for hit in results["result"]["hits"]
)
```
Give your LLM the ability to call the search function when it needs information.
```python Anthropic (Claude) theme={null}
tools = [{
"name": "search_knowledge_base",
"description": "Search the company knowledge base for policies, specs, HR info, and procedures.",
"input_schema": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "The search query"}
},
"required": ["query"]
}
}]
def ask(question: str) -> str:
messages = [{"role": "user", "content": question}]
# disable_parallel_tool_use keeps this loop simple: with parallel calls,
# every tool_use block would need a matching tool_result in the next message
response = llm.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
tools=tools,
tool_choice={"type": "auto", "disable_parallel_tool_use": True},
messages=messages
)
# If the model wants to use a tool, call it and return the result
while response.stop_reason == "tool_use":
tool_block = next(b for b in response.content if b.type == "tool_use")
tool_result = search_knowledge_base(tool_block.input["query"])
messages += [
{"role": "assistant", "content": response.content},
{"role": "user", "content": [{
"type": "tool_result",
"tool_use_id": tool_block.id,
"content": tool_result
}]}
]
response = llm.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
tools=tools,
tool_choice={"type": "auto", "disable_parallel_tool_use": True},
messages=messages
)
return next(b.text for b in response.content if hasattr(b, "text"))
```
```python OpenAI theme={null}
import json
tools = [{
"type": "function",
"function": {
"name": "search_knowledge_base",
"description": "Search the company knowledge base for policies, specs, HR info, and procedures.",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "The search query"}
},
"required": ["query"]
}
}
}]
def ask(question: str) -> str:
messages = [{"role": "user", "content": question}]
# parallel_tool_calls=False keeps this loop simple: with parallel calls,
# every tool call would need a matching tool message in the next turn
response = llm.chat.completions.create(
model="gpt-4o",
tools=tools,
parallel_tool_calls=False,
messages=messages
)
# If the model wants to use a tool, call it and return the result
while response.choices[0].finish_reason == "tool_calls":
tool_call = response.choices[0].message.tool_calls[0]
args = json.loads(tool_call.function.arguments)
tool_result = search_knowledge_base(args["query"])
messages += [
response.choices[0].message,
{"role": "tool", "tool_call_id": tool_call.id, "content": tool_result}
]
response = llm.chat.completions.create(
model="gpt-4o",
tools=tools,
parallel_tool_calls=False,
messages=messages
)
return response.choices[0].message.content
```
```python theme={null}
print(ask("What's the refund policy?"))
```
If the agent says it can't find the information, wait a few seconds and retry. Pinecone is eventually consistent, so freshly upserted records take a moment to become searchable.
Your agent searches Pinecone, retrieves the relevant policy, and answers:
```console Output theme={null}
Refund requests must be submitted within 30 days of purchase. After that
30-day window, you can still receive store credit but not a direct refund.
```
Try a few more questions:
```python theme={null}
print(ask("How much PTO do new employees get?"))
print(ask("What approval do I need for a $15,000 vendor invoice?"))
```
**What just happened:** Your LLM received a question, decided it needed more information, and called the `search_knowledge_base` tool. Pinecone returned the most relevant records with reranking, and the LLM synthesized an accurate answer from the retrieved context. Production RAG agents use this same pattern, and the `search_knowledge_base` function works in any agent framework.
### Next steps
Add conversation history, streaming, and a web UI
Explore semantic, hybrid, and full-text search
Model your data for efficient retrieval
***
## Integrate the SDK directly
Integrate Pinecone directly into your application. Use these SDK calls wherever your code needs knowledge retrieval, whether that's an agent, a backend service, or a standalone script.
To get started in your browser, use the [Quickstart colab notebook](https://colab.research.google.com/github/pinecone-io/examples/blob/master/docs/pinecone-quickstart.ipynb).
### 1. Install an SDK
```shell Python theme={null}
pip install pinecone
```
```shell JavaScript theme={null}
npm install @pinecone-database/pinecone
```
```shell Java theme={null}
# Maven
io.pineconepinecone-client5.0.0
# Gradle
implementation "io.pinecone:pinecone-client:5.0.0"
```
```shell Go theme={null}
go get github.com/pinecone-io/go-pinecone/v4/pinecone
```
### 2. Create an index
Create an [index with integrated embedding](/guides/index-data/create-an-index#create-an-index-for-dense-vectors) so you can upsert and search with text. Pinecone generates the vectors for you.
If you prefer to use external embedding models, see [Bring your own vectors](/guides/index-data/indexing-overview#bring-your-own-vectors).
```python Python theme={null}
from pinecone import Pinecone
pc = Pinecone(api_key="{{YOUR_API_KEY}}")
index_name = "quickstart-py"
if not pc.has_index(index_name):
pc.create_index_for_model(
name=index_name,
cloud="aws",
region="us-east-1",
embed={
"model":"llama-text-embed-v2",
"field_map":{"text": "chunk_text"}
}
)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({ apiKey: '{{YOUR_API_KEY}}' });
const indexName = 'quickstart-js';
await pc.createIndexForModel({
name: indexName,
cloud: 'aws',
region: 'us-east-1',
embed: {
model: 'llama-text-embed-v2',
fieldMap: { text: 'chunk_text' },
},
waitUntilReady: true,
});
```
```java Java theme={null}
import io.pinecone.clients.Index;
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.ApiException;
import org.openapitools.db_control.client.model.CreateIndexForModelRequest;
import org.openapitools.db_control.client.model.CreateIndexForModelRequestEmbed;
import org.openapitools.db_control.client.model.DeletionProtection;
import org.openapitools.db_control.client.model.IndexModel;
import org.openapitools.db_data.client.model.SearchRecordsRequestQuery;
import org.openapitools.db_data.client.model.SearchRecordsResponse;
import io.pinecone.proto.DescribeIndexStatsResponse;
import java.util.*;
public class Quickstart {
public static void main(String[] args) throws ApiException {
Pinecone pc = new Pinecone.Builder("{{YOUR_API_KEY}}").build();
String indexName = "quickstart-java";
String region = "us-east-1";
HashMap fieldMap = new HashMap<>();
fieldMap.put("text", "chunk_text");
CreateIndexForModelRequestEmbed embed = new CreateIndexForModelRequestEmbed()
.model("llama-text-embed-v2")
.fieldMap(fieldMap);
IndexModel index = pc.createIndexForModel(
indexName,
CreateIndexForModelRequest.CloudEnum.AWS,
region,
embed,
DeletionProtection.DISABLED,
null
);
}
}
```
```go Go theme={null}
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "{{YOUR_API_KEY}}",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
indexName := "quickstart-go"
index, err := pc.CreateIndexForModel(ctx, &pinecone.CreateIndexForModelRequest{
Name: indexName,
Cloud: pinecone.Aws,
Region: "us-east-1",
Embed: pinecone.CreateIndexForModelEmbed{
Model: "llama-text-embed-v2",
FieldMap: map[string]interface{}{"text": "chunk_text"},
},
})
if err != nil {
log.Fatalf("Failed to create serverless index: %v", err)
} else {
fmt.Printf("Successfully created serverless index: %v", index.Name)
}
}
func prettifyStruct(obj interface{}) string {
bytes, _ := json.MarshalIndent(obj, "", " ")
return string(bytes)
}
```
### 3. Upsert data
Load records into your index. Each record has an ID, text content, and optional metadata. Pinecone converts the text to vectors automatically using the integrated embedding model.
```python Python [expandable] theme={null}
index = pc.Index(index_name)
index.upsert_records(
namespace="example-namespace",
records=[
{"_id": "rec1", "chunk_text": "The Eiffel Tower was completed in 1889 and stands in Paris, France.", "category": "history"},
{"_id": "rec2", "chunk_text": "Photosynthesis allows plants to convert sunlight into energy.", "category": "science"},
{"_id": "rec3", "chunk_text": "Albert Einstein developed the theory of relativity.", "category": "science"},
{"_id": "rec4", "chunk_text": "The mitochondrion is often called the powerhouse of the cell.", "category": "biology"},
{"_id": "rec5", "chunk_text": "Shakespeare wrote many famous plays, including Hamlet and Macbeth.", "category": "literature"},
{"_id": "rec6", "chunk_text": "The Great Wall of China was built to protect against invasions.", "category": "history"},
{"_id": "rec7", "chunk_text": "The Pyramids of Giza are among the Seven Wonders of the Ancient World.", "category": "history"},
{"_id": "rec8", "chunk_text": "Leonardo da Vinci painted the Mona Lisa.", "category": "art"},
{"_id": "rec9", "chunk_text": "The internet revolutionized communication and information sharing.", "category": "technology"},
{"_id": "rec10", "chunk_text": "Renewable energy sources include wind, solar, and hydroelectric power.", "category": "energy"},
]
)
```
```javascript JavaScript [expandable] theme={null}
const namespace = pc.index(indexName).namespace("example-namespace");
await namespace.upsertRecords({ records: [
{"_id": "rec1", "chunk_text": "The Eiffel Tower was completed in 1889 and stands in Paris, France.", "category": "history"},
{"_id": "rec2", "chunk_text": "Photosynthesis allows plants to convert sunlight into energy.", "category": "science"},
{"_id": "rec3", "chunk_text": "Albert Einstein developed the theory of relativity.", "category": "science"},
{"_id": "rec4", "chunk_text": "The mitochondrion is often called the powerhouse of the cell.", "category": "biology"},
{"_id": "rec5", "chunk_text": "Shakespeare wrote many famous plays, including Hamlet and Macbeth.", "category": "literature"},
{"_id": "rec6", "chunk_text": "The Great Wall of China was built to protect against invasions.", "category": "history"},
{"_id": "rec7", "chunk_text": "The Pyramids of Giza are among the Seven Wonders of the Ancient World.", "category": "history"},
{"_id": "rec8", "chunk_text": "Leonardo da Vinci painted the Mona Lisa.", "category": "art"},
{"_id": "rec9", "chunk_text": "The internet revolutionized communication and information sharing.", "category": "technology"},
{"_id": "rec10", "chunk_text": "Renewable energy sources include wind, solar, and hydroelectric power.", "category": "energy"},
] });
```
```java Java [expandable] theme={null}
// Add to the Quickstart class:
Index index = pc.getIndexConnection(indexName);
ArrayList
Pinecone is eventually consistent. New records may take a few seconds to become searchable.
### 4. Search and rerank
Search the index for records semantically similar to a query, then [rerank](/guides/search/rerank-results) for more accurate results.
```python Python theme={null}
query = "Famous historical structures and monuments"
results = index.search(
namespace="example-namespace",
query={
"top_k": 10,
"inputs": {"text": query}
},
rerank={
"model": "bge-reranker-v2-m3",
"top_n": 5,
"rank_fields": ["chunk_text"]
}
)
for hit in results["result"]["hits"]:
print(f"score: {round(hit.score, 2):<5} | {hit.fields['chunk_text']}")
```
```console Output theme={null}
score: 0.11 | The Eiffel Tower was completed in 1889 and stands in Paris, France.
score: 0.06 | The Great Wall of China was built to protect against invasions.
score: 0.02 | The Pyramids of Giza are among the Seven Wonders of the Ancient World.
score: 0.01 | Leonardo da Vinci painted the Mona Lisa.
score: 0.0 | Shakespeare wrote many famous plays, including Hamlet and Macbeth.
```
```javascript JavaScript theme={null}
const query = 'Famous historical structures and monuments';
const results = await namespace.searchRecords({
query: {
topK: 10,
inputs: { text: query },
},
rerank: {
model: 'bge-reranker-v2-m3',
topN: 5,
rankFields: ['chunk_text'],
},
});
results.result.hits.forEach(hit => {
console.log(`score: ${hit._score.toFixed(2)}, text: ${hit.fields.chunk_text}`);
});
```
```java Java theme={null}
// Add to the Quickstart class:
String query = "Famous historical structures and monuments";
List fields = new ArrayList<>();
fields.add("category");
fields.add("chunk_text");
List rankFields = new ArrayList<>();
rankFields.add("chunk_text");
SearchRecordsRequestRerank rerank = new SearchRecordsRequestRerank()
.query(query)
.model("bge-reranker-v2-m3")
.topN(5)
.rankFields(rankFields);
SearchRecordsResponse response = index.searchRecordsByText(
query, "example-namespace", fields, 10, null, rerank
);
System.out.println(response);
```
```go Go theme={null}
// Add to the main function:
query := "Famous historical structures and monuments"
topN := int32(5)
res, err := idxConnection.SearchRecords(ctx, &pinecone.SearchRecordsRequest{
Query: pinecone.SearchRecordsQuery{
TopK: 10,
Inputs: &map[string]interface{}{
"text": query,
},
},
Rerank: &pinecone.SearchRecordsRerank{
Model: "bge-reranker-v2-m3",
TopN: &topN,
RankFields: []string{"chunk_text"},
},
})
if err != nil {
log.Fatalf("Failed to search records: %v", err)
}
fmt.Printf(prettifyStruct(res))
```
### 5. Clean up
When you no longer need the example index, delete it:
```python Python theme={null}
pc.delete_index(index_name)
```
```javascript JavaScript theme={null}
await pc.deleteIndex(indexName);
```
```java Java theme={null}
pc.deleteIndex(indexName);
```
```go Go theme={null}
err = pc.DeleteIndex(ctx, indexName)
if err != nil {
log.Fatalf("Failed to delete index: %v", err)
}
```
For production indexes, consider [enabling deletion protection](/guides/manage-data/manage-indexes#configure-deletion-protection).
### Next steps
Learn more about storing data in Pinecone
Explore different forms of vector search
Find out how to improve performance
***
## No-code with n8n
Create an AI workflow that uses Pinecone for knowledge retrieval without writing any code.
Use [n8n](https://docs.n8n.io/choose-n8n/) to create a workflow that downloads files via HTTP and lets you chat with them using Pinecone Database and OpenAI.
If you're not interested in chunking and embedding your own data, [use n8n with Pinecone Assistant](/guides/assistant/quickstart/n8n-quickstart) instead.
### 1. Get an OpenAI API key
Create a new API key in the [OpenAI console](https://platform.openai.com/api-keys).
### 2. Create an index
[Create an index](https://app.pinecone.io/organizations/-/projects/-/create-index/serverless) in the Pinecone console:
* Name your index `n8n-dense-index`
* Under **Configuration**, check **Custom settings** and set **Dimension** to 1536.
* Leave everything else as default.
### 3. Set up n8n
In your n8n account, [create a new workflow](https://docs.n8n.io/workflows/create/).
Copy this workflow template URL:
```shell theme={null}
https://raw.githubusercontent.com/pinecone-io/n8n-templates/refs/heads/main/database-quickstart/database-quickstart.json
```
Paste the URL into the workflow editor and then click **Import** to add the workflow.
* Add your Pinecone credentials:
* In the **Pinecone Vector Store** node, select **Credential to connect with** > **Create new credential** and paste in your Pinecone API key.
* Name the credential **Pinecone** so that other nodes reference it.
* Add your OpenAI credentials:
* In the **OpenAI Chat Model**, select **Credential to connect with** > **Create new credential** and paste in your OpenAI API key.
The workflow is configured to download recent Pinecone release notes and upload them to your Pinecone index. Click **Execute workflow** to start the workflow.
You can add your own files to the workflow by changing the URLs in the **Set file urls** node.
### 4. Chat with your docs
Once the workflow is activated, ask it for the latest changes to Pinecone Database:
```
What's new in Pinecone Database?
```
### Next steps
* Use your own data:
* Change the urls in **Set file urls** node to use your own files.
* You may need to adjust the chunk sizes in the **Recursive Character Text Splitter** node or use a different chunking strategy. See [Chunking Strategies for LLM Applications](https://www.pinecone.io/learn/chunking-strategies/) for more info.
* Customize the system message of the **AI Agent** node to reflect what the **Pinecone Vector Store Tool** will be used for.
* Customize the description of the **Pinecone Vector Store Tool** to reflect what data you are storing in the Pinecone index.
* Use n8n, Pinecone Assistant, and OpenAI to [chat with your Google Drive documents](https://n8n.io/workflows/9942-rag-powered-document-chat-with-google-drive-openai-and-pinecone-assistant/).
* Get help in the [Pinecone Discord community](https://discord.gg/tJ8V62S3sH).
# Test Pinecone at scale
Source: https://docs.pinecone.io/guides/get-started/test-at-scale
Benchmark Pinecone at production scale by importing 10M vectors and measuring semantic search throughput, query latency, and costs.
This guide walks you through testing Pinecone at production scale. You'll import 10 million vectors, run a benchmark, and analyze the results to verify Pinecone meets production requirements for semantic search applications.
This test requires a Pinecone account on the Standard or Enterprise plan because it uses [import from object storage](/guides/index-data/import-data), which is not available on the Starter or Builder plans. New users can sign up for the [Standard trial](/guides/organizations/manage-billing/standard-trial) for 21 days and \$300 in credits, more than enough to cover the costs of this test. Existing users on the Starter or Builder plan can [upgrade](/guides/organizations/manage-billing/upgrade-billing-plan).
## About this test
Semantic search enables finding relevant content based on meaning rather than exact keyword matches, making it ideal for applications like product search, content recommendation, and question-answering systems. This test simulates a production-scale semantic search workload, measuring import time, query throughput, query latency, and associated costs.
The test uses the following configuration:
* **Records**: 10 million records from the [Amazon Reviews 2023](https://amazon-reviews-2023.github.io/) dataset
* **Embedding model**: `llama-text-embed-v2` (1024 dimensions)
* **Similarity metric**: cosine
* **Total size**: 48.8 GB
* **Query load**: 10 queries per second total (across all users)
* **Concurrent users**: 10 users querying simultaneously
* **Test queries**: 100,000 queries
* **Import time target**: \< 30 minutes
* **Query latency target**: p90 latency \< 100ms
**Estimated cost**: \~\$127 (import: \$48.80, queries: \$78.08, storage: \$0.09) — see [detailed cost breakdown](#6-check-costs)
## 1. Get an API key
To follow the steps in this guide, you'll need an API key. Create a new API key in the [Pinecone console](https://app.pinecone.io/organizations/-/keys), or use this widget:
Your generated API key:
```shell theme={null}
"{{YOUR_API_KEY}}"
```
## 2. Create an index
This test requires you to use AWS-based indexes and infrastructure. The sample dataset is only available from Amazon S3, and you can only import from Amazon S3 to Pinecone indexes hosted on AWS. To run the benchmark, you'll need to provision an AWS EC2 instance in the same region as your index.
Create an on-demand index that matches the dimensions and similarity metric of the dataset you'll import in later steps.
1. In the Pinecone console, go to the [Indexes](https://app.pinecone.io/organizations/-/projects/-/indexes) page.
2. Click **Create index**.
3. Check **Custom settings**.
4. Configure the index with the following settings:
* **Name**: `search-10m`
* **Vector type**: Dense
* **Dimensions**: `1024`
* **Metric**: cosine
* **Capacity mode**: Serverless (on-demand)
* **Cloud**: AWS (required for this test)
* **Region**: Use an AWS region appropriate for your use case (for example, `us-east-1`)
5. Click **Create index**.
If using code to create an index, first install the [Python SDK](/reference/python-sdk):
```shell Terminal theme={null}
pip install pinecone
```
Then, create the index:
```python Python theme={null}
from pinecone import Pinecone, ServerlessSpec
pc = Pinecone(api_key="{{YOUR_API_KEY}}")
index_name = "search-10m"
if not pc.has_index(index_name):
pc.create_index(
name=index_name,
vector_type="dense",
dimension=1024,
metric="cosine",
spec=ServerlessSpec(
# AWS is required for this test
cloud="aws",
# Use an AWS region appropriate for your use case
region="us-east-1"
)
)
```
## 3. Import the dataset
Pinecone's [import feature](/guides/index-data/import-data) enables you to load millions of vectors from object storage in parallel. In this step, you'll import 10 million records into a single namespace (`ns_2`) in your index.
### Choose an import source
To import the dataset, you'll need to use the following Amazon S3 import URL:
```
s3://fe-customer-pocs/search/search_10M/dense/
```
### Start and monitor the import
For this dataset, the import should take less than 30 minutes.
1. In the Pinecone console, go to the [Indexes](https://app.pinecone.io/organizations/-/projects/-/indexes) page.
2. Find your `search-10m` index and click **... > Import data**.
3. For **Storage integration**, select **No integration (public bucket)**.
4. Enter the import URL: `s3://fe-customer-pocs/search/search_10M/dense/`.
5. For **Error handling**, select **Abort on error (default)**.
6. Click **Start import**.
To monitor progress, open your index in the Pinecone console and navigate to the **Imports** tab. After the import completes, compare the **Started time** and **End time** timestamps to see the total time required.
For this dataset, the import should take around 30 minutes. While the import is running, you can continue with the next step to provision a VM and install VSB. However, wait for the import to complete before running the benchmark.
Start the import:
```python Python theme={null}
from pinecone import Pinecone, ImportErrorMode
pc = Pinecone(api_key="{{YOUR_API_KEY}}")
index = pc.Index("search-10m")
import_response = index.start_import(
uri="s3://fe-customer-pocs/search/search_10M/dense/",
error_mode=ImportErrorMode.ABORT
)
print(f"Import started: {import_response['id']}")
```
Monitor import progress:
```python Python theme={null}
from pinecone import Pinecone
import time
pc = Pinecone(api_key="{{YOUR_API_KEY}}")
index = pc.Index("search-10m")
while True:
status = index.describe_import(id="IMPORT_ID")
print(f"Status: {status['status']}, Progress: {status['percent_complete']:.1f}%")
if status['status'] == "Completed":
print("Import completed successfully!")
break
elif status['status'] == "Failed":
print("Import failed. Check error details.")
break
elif status['status'] == "Cancelled":
print("Import cancelled.")
break
time.sleep(15) # Check every 15 seconds
```
There are three ways to find the import ID:
* It's returned when the import is started
* In the Pinecone console, on the **Imports** tab for your index
* By calling [List imports](/reference/api/latest/data-plane/list_imports)
## 4. Run the benchmark
To simulate realistic query patterns and measure latency and throughput for your Pinecone index, use [Vector Search Bench (VSB)](https://github.com/pinecone-io/VSB). The benchmark runs 100,000 queries at 10 queries per second, which should take just under three hours to complete.
VSB reports latency as the time from when the tool issues a query to when the query is returned by Pinecone.
To minimize the client-side latency between the tool and Pinecone, run the benchmark on a dedicated AWS EC2 instance that's hosted in the same AWS region as your Pinecone index. This reduces the client-side latency to sub-millisecond range.
As noted in [section 2](#2-create-an-index), this test requires an AWS EC2 instance in the same region as your index.
For instructions on how to provision an EC2 instance, see the [AWS documentation](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/LaunchingAndUsingInstances.html).
Create a VM that comes with Python 3.11 or higher.
Connect to the VM using SSH or the cloud provider's console.
[VSB (Vector Search Bench)](https://github.com/pinecone-io/VSB) is a benchmarking suite for testing vector database search performance across different workloads and databases. To install it, you'll first need to install various dependencies.
1. **Verify Python version**
VSB requires Python 3.11 or higher to run. Verify your Python version:
```bash Terminal theme={null}
python3 --version
```
If your version is below 3.11, install Python 3.11+ using your distribution's package manager.
2. **Install git**
Git is required to clone the VSB repository. Check if git is installed:
```bash Terminal theme={null}
git --version
```
If git is not installed, install it using your system's package manager:
```bash Terminal theme={null}
# Adapt for your VM's package manager (apt/yum/dnf)
sudo apt-get update && sudo apt-get install git
```
3. **Install pipx**
pipx is required to install Poetry. First, check if pip3 is installed:
```bash Terminal theme={null}
pip3 --version
```
If pip is not installed, install it using your system's package manager:
```bash Terminal theme={null}
# Adapt for your VM's package manager (apt/yum/dnf)
sudo apt-get update && sudo apt-get install python3-pip
```
Then check if pipx is installed:
```bash Terminal theme={null}
pipx --version
```
If pipx is not installed, install it via your system's package manager:
```bash Terminal theme={null}
# Adapt for your VM's package manager (apt/yum/dnf)
sudo apt-get update && sudo apt-get install pipx
pipx ensurepath
```
After installation, run this command to update the PATH in your current terminal session:
```bash Terminal theme={null}
source ~/.bashrc
```
4. **Install Poetry**
[Poetry](https://python-poetry.org/) is required to manage [VSB's](https://github.com/pinecone-io/VSB) Python dependencies and virtual environment. If Poetry is not [installed](https://python-poetry.org/docs/), use pipx to install it:
```bash Terminal theme={null}
pipx install poetry
```
Alternatively, use the [official Poetry installer](https://python-poetry.org/docs/#installing-with-the-official-installer).
5. **Clone the VSB repository**
To run the benchmark, you'll first need to clone the VSB repository and navigate to it:
```bash Terminal theme={null}
git clone https://github.com/pinecone-io/VSB.git
cd VSB
```
6. **Configure Poetry**
Since your VM has Python 3.11 or higher installed (as specified in the VM provisioning step), tell Poetry to use it:
```bash Terminal theme={null}
poetry env use python3
```
7. **Install dependencies**
VSB requires several Python packages to run. Install all dependencies:
```bash Terminal theme={null}
poetry install
```
To test the performance of your Pinecone index, run the following command from within the `VSB` directory. For more information about VSB, see its [GitHub repository](https://github.com/pinecone-io/VSB).
The following command simulates 10 concurrent users issuing a total of 100,000 queries at 10 queries per second (QPS). Each query performs a vector search for the top 10 most similar 1024-dimensional vectors, using cosine similarity, with query vectors selected uniformly at random. The `--skip_populate` flag skips the data population phase, since you've already imported data into your index.
```bash Terminal theme={null}
poetry run vsb \
--database="pinecone" \
--workload=synthetic-proportional \
--pinecone_api_key="{{YOUR_API_KEY}}" \
--pinecone_index_name="search-10m" \
--pinecone_namespace_name="ns_2" \
--synthetic_dimensions=1024 \
--synthetic_metric=cosine \
--synthetic_top_k=10 \
--synthetic_requests=100000 \
--users=10 \
--requests_per_sec=10 \
--synthetic_query_distribution=uniform \
--synthetic_query_ratio=1 \
--synthetic_insert_ratio=0 \
--synthetic_delete_ratio=0 \
--synthetic_update_ratio=0 \
--skip_populate
```
## 5. Analyze performance
At the end of the run, VSB prints an operation summary including the requests per second achieved and latencies at different percentiles. Here's an example output:
```shell Terminal theme={null}
2025-12-23T00:34:37 INFO Completed Run phase, took 9940.14s
Operation Summary
Operation Requests Failures Requests/sec Failures/sec
───────────────────────────────────────────────────────────
Search 99000 0(0%) 10 0.0
Metrics Summary
Operation Metric Min 0.1% 1% 5% 10% 25% 50% 75% 90% 95% 99% 99.9% 99.99% Max Mean
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Search Latency (ms) 23 25 25 26 27 27 29 34 44 81 350 430 1300 4602 43
```
Confirm that the requests per second achieved is around 10 QPS and the p90 latency is less than 100ms.
To see more detailed statistics, you can analyze the `stats.json` file identified in the output.
## 6. Check costs
You can check the costs for the import, queries, and storage in the Pinecone console at [Settings > Usage](https://app.pinecone.io/organizations/-/settings/usage). Cost data is delayed up to three days, but once it's available, compare the actual costs to the estimated costs below.
For the latest pricing details, see [Pricing](https://www.pinecone.io/pricing).
| Cost type | Amount | Pricing | Estimated cost |
| :-------- | :-------------- | :--------------------- | :------------- |
| Import | 48.8 GB | \$0.25/GB | \$12.20 |
| Queries | 100,000 queries | \$16 per 1M read units | \$78.08 |
| Storage | 4 hours | \$0.33/GB/month | \$0.09 |
| **Total** | | | **\$90.37** |
Standard and Enterprise organizations receive a **one-time 1 TB bulk import credit**, valid through August 30, 2026, so on those plans the import portion of this example would be \$0 and the total would be \$78.17. The figures above assume the standard overage rate.
The current price for import is \$0.25/GB. The dataset size for this test is 48.8 GB, so the import cost should be \$12.20.
A query uses 1 [read unit (RU)](/guides/manage-cost/understanding-cost#read-units) for every 1 GB of namespace size. The current price for queries in the `us-east-1` region of AWS is \$16 per 1 million read units (pricing varies by region).
This test ran 100,000 queries against a namespace size of 48.8 GB. Each query uses 48.8 RUs (1 RU per GB), so the total is 4,880,000 RUs. At \$16 per 1 million RUs, the cost is (4,880,000 / 1,000,000) × \$16 = \$78.08.
The current price for storage is \$0.33 per GB per month. The dataset size for this test is 48.8 GB. Assuming a total storage time of 4 hours (including import, benchmark runtime, and cleanup), the storage cost is: \$0.33/GB/month \* 48.8 GB / 730 hours \* 4 hours = \$0.09.
The total cost for the test is the sum of the import cost, query cost, and storage cost: \$12.20 + \$78.08 + \$0.09 = \$90.37.
## 7. Clean up
When you no longer need your test index, [delete it](/guides/manage-data/manage-indexes#delete-an-index) to avoid incurring unnecessary costs.
# Check data freshness
Source: https://docs.pinecone.io/guides/index-data/check-data-freshness
Check data freshness in Pinecone serverless indexes using log sequence numbers (LSNs) and vector counts to verify recent upserts and deletes.
Pinecone is eventually consistent, so there can be a slight delay before new or changed records are visible to queries. This page describes two ways of checking the data freshness of a Pinecone index:
* To check if a serverless index queries reflect recent writes to the index, [check the log sequence number](#check-the-log-sequence-number).
* To check whether an index contains recently inserted or deleted vectors, [verify the number of vectors in the index](#verify-vector-counts).
## Check the log sequence number
This method is only available for serverless indexes through the [Database API](https://docs.pinecone.io/reference/api/latest/data-plane/upsert).
### Log sequence numbers
When you make a write request to a serverless index namespace, Pinecone assigns a monotonically increasing log sequence number (LSN) to the write operation. The LSN reflects upserts as well as updates and deletes to that namespace. Writes to one namespace do not increase the LSN for other namespaces.
You can use LSNs to verify that specific write operations are reflected in your query responses. If the LSN contained in the query response header is greater than or equal to the LSN of the relevant write operation, then that operation is reflected in the query response. If the LSN contained in the query response header is *greater than* the LSN of the relevant write operation, then subsequent operations are also reflected in the query response.
Follow the steps below to compare the LSNs for a write and a subsequent query.
### 1. Get the LSN for a write operation
Every time you modify records in your namespace, the HTTP response contains the LSN for the upsert. This is contained in a header called `x-pinecone-request-lsn`.
The following example demonstrates how to get the LSN for an `upsert` request using the `curl` option `-i`. This option tells curl to include headers in the displayed response. Use the same method to get the LSN for an `update` or `delete` request.
```shell curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
curl -i "https://$INDEX_HOST/vectors/upsert" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "content-type: application/json" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"vectors": [
{
"id": "vec1",
"values": [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8],
}
],
"namespace": "example-namespace"
}'
```
The preceding request receives a response like the following example:
```shell curl theme={null}
HTTP/2 200
date: Wed, 21 Aug 2024 15:23:04 GMT
content-type: application/json
content-length: 66
x-pinecone-request-lsn: 4
x-pinecone-request-latency-ms: 1149
x-pinecone-request-id: 3687967458925971419
x-envoy-upstream-service-time: 1150
grpc-status: 0
server: envoy
{"upsertedCount":1}
```
In the preceding example response, the value of `x-pinecone-request-lsn` is 4. This is the LSN assigned to this write operation; use it to compare against the query response LSN in the next step.
### 2. Get the LSN for a query
Every time you query your index, the HTTP response contains the LSN for the query. This is contained in a header called `x-pinecone-max-indexed-lsn`.
By checking the LSN in your query results, you can confirm that the LSN is greater than or equal to the LSN of the relevant write operation, indicating that the results of that operation are present in the query results.
The following example makes a `query` request to the index:
```shell curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
curl -i "https://$INDEX_HOST/query" \
-H "Api-Key: $PINECONE_API_KEY" \
-H 'Content-Type: application/json' \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"vector": [0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3],
"namespace": "example-namespace",
"topK": 3,
"includeValues": true
}'
```
The preceding request receives a response like the following example:
```shell theme={null}
HTTP/2 200
date: Wed, 21 Aug 2024 15:33:36 GMT
content-type: application/json
content-length: 66
x-pinecone-max-indexed-lsn: 5
x-pinecone-request-latency-ms: 40
x-pinecone-request-id: 6683088825552978933
x-envoy-upstream-service-time: 41
grpc-status: 0
server: envoy
{
"results":[],
"matches":[
{
"id":"vec1",
"score":0.891132772,
"values":[0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8],
}
],
"namespace":"example-namespace",
"usage":{"readUnits":6}
}
```
In the preceding example response, the value of `x-pinecone-max-indexed-lsn` is 5.
### 3. Compare LSNs for writes and queries
If the LSN of a query is greater than or equal to the LSN for a write operation, then the results of the query reflect the results of the write operation.
In [step 1](#1-get-the-lsn-for-a-write-operation), the LSN contained in the response headers is 4.
In [step 2](#2-get-the-lsn-for-a-query), the LSN contained in the response headers is 5.
5 is greater than or equal to 4; therefore, the results of the query reflect the results of the upsert. However, this does not guarantee that the records upserted are still present or unmodified: the write operation with LSN of 5 may have updated or deleted these records, or upserted additional records.
## Verify record counts
If you insert new records or delete records, the number of records in the index may change. This means that the record count for an index can indicate whether Pinecone has indexed your latest inserts and deletes: if the record count for the index matches the count you expect after inserting or deleting records, the index is probably up-to-date. However, this is not always true. For example, if you delete the same number of records that you insert, the expected record count may remain the same. Also, some write operations, such as updates to an index configuration or vector data values, do not change the number of records in the index.
To verify that your index contains the number of records you expect, [view index stats](/reference/api/latest/data-plane/describeindexstats):
```python Python theme={null}
# pip install "pinecone[grpc]"
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
index = pc.Index(host="INDEX_HOST")
index.describe_index_stats()
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' })
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
const index = pc.index("INDEX_NAME", "INDEX_HOST")
const stats = await index.describeIndexStats();
```
```java Java theme={null}
import io.pinecone.clients.Index;
import io.pinecone.configs.PineconeConfig;
import io.pinecone.configs.PineconeConnection;
import io.pinecone.proto.DescribeIndexStatsResponse;
public class DescribeIndexStatsExample {
public static void main(String[] args) {
PineconeConfig config = new PineconeConfig("YOUR_API_KEY");
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
config.setHost("INDEX_HOST");
PineconeConnection connection = new PineconeConnection(config);
Index index = new Index(connection, "INDEX_NAME");
DescribeIndexStatsResponse indexStatsResponse = index.describeIndexStats();
System.out.println(indexStatsResponse);
}
}
```
```go Go theme={null}
package main
import (
"context"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
idxConnection, err := pc.Index(pinecone.NewIndexConnParams{Host: "INDEX_HOST"})
if err != nil {
log.Fatalf("Failed to create IndexConnection for Host: %v", err)
}
stats, err := idxConnection.DescribeIndexStats(ctx)
if err != nil {
log.Fatalf("Failed to describe index \"%v\": %v", idx.Name, err)
} else {
fmt.Printf("%+v", *stats)
}
}
```
```shell curl theme={null}
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
curl -X POST "https://$INDEX_HOST/describe_index_stats" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10"
```
The response will look like this:
```Python Python theme={null}
{'dimension': 1024,
'index_fullness': 0,
'namespaces': {'example-namespace1': {'vector_count': 4}, 'example-namespace2': {'vector_count': 4}},
'total_vector_count': 8}
```
```JavaScript JavaScript theme={null}
Returns:
{
namespaces: { example-namespace1: { recordCount: 4 }, example-namespace2: { recordCount: 4 } },
dimension: 1024,
indexFullness: 0,
totalRecordCount: 8
}
// Note: the value of totalRecordCount is the same as total_vector_count.
```
```java Java theme={null}
namespaces {
key: "example-namespace1"
value {
vector_count: 4
}
}
namespaces {
key: "example-namespace2"
value {
vector_count: 4
}
}
dimension: 1024
total_vector_count: 8
```
```go Go theme={null}
{
"dimension": 1024,
"index_fullness": 0,
"total_vector_count": 8,
"namespaces": {
"example-namespace1": {
"vector_count": 4
},
"example-namespace2": {
"vector_count": 4
}
}
}
```
```shell curl theme={null}
{
"namespaces": {
"example-namespace1": {
"vectorCount": 4
},
"example-namespace2": {
"vectorCount": 4
}
},
"dimension": 1024,
"indexFullness": 0,
"totalVectorCount": 8
}
```
# Create an index
Source: https://docs.pinecone.io/guides/index-data/create-an-index
Create a Pinecone serverless index for full-text (BM25), semantic (dense vector), lexical (sparse), or hybrid search with a document schema.
A Pinecone index can hold any combination of the following:
* **Documents** are the unit of data in an index with a document schema — JSON records whose ranking fields are indexed according to a schema you declare at index creation. An index with a document schema can mix `dense_vector`, `sparse_vector`, and FTS-enabled `string` ranking fields in the same record, alongside any number of metadata fields (auto-indexed at upsert time). Use documents for [full-text search](/guides/search/full-text-search) (BM25 ranking on `string` fields with `full_text_search` enabled), and to combine multiple scoring methods on the same data via `score_by`.
* **Dense vectors** are numerical representations of the meaning and relationships of text, images, or other data. Indexes of dense vectors are used for [semantic search](/guides/search/semantic-search), or together with sparse vectors for [hybrid search](/guides/search/hybrid-search).
* **Sparse vectors** are high-dimensional vectors with mostly zero values, produced by a sparse embedding model such as [`pinecone-sparse-english-v0`](/models/pinecone-sparse-english-v0). Indexes of sparse vectors are used for [sparse-vector lexical search](/guides/search/lexical-search), or together with dense vectors for [hybrid search](/guides/search/hybrid-search).
You can create an index using the [Pinecone console](https://app.pinecone.io/organizations/-/projects/-/create-index/serverless).
## Create an index for full-text search
An index with a document schema stores typed JSON documents. The schema declares how each ranking field is indexed: as a `string` field with `full_text_search` enabled for BM25 ranking, a `dense_vector` for ANN similarity, or a `sparse_vector`. A single index can mix all three ranking field types; at query time, pick the ranking signal with `score_by`. Metadata fields (anything else you upsert) are not declared in the schema — they're auto-indexed for filtering at upsert time.
Full-text search is not integrated embedding. A `string` field with `full_text_search` is indexed for BM25 ranking and Lucene queries. It does not call an embedding model. Integrated embedding remains available for vector API indexes.
Indexes with document schemas are in [public preview](/guides/search/full-text-search#public-preview) and use API version `2026-01.alpha`. The preview supports REST and the Python SDK; for other languages, call the REST endpoint directly.
### Minimal: BM25 on a single text field
The example below creates an `articles` index whose `body` field is indexed for BM25 ranking. Other fields included at upsert time are stored on each document and auto-indexed for filtering as metadata.
```bash curl theme={null}
curl -X POST "https://api.pinecone.io/indexes" \
-H "Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "X-Pinecone-Api-Version: 2026-01.alpha" \
-d '{
"name": "articles",
"deployment": {
"deployment_type": "managed",
"cloud": "aws",
"region": "us-east-1"
},
"schema": {
"fields": {
"body": {
"type": "string",
"full_text_search": {}
}
}
}
}'
```
### Multi-field schema: BM25 + dense vector
A single index with a document schema can hold FTS-enabled `string` and `dense_vector` ranking fields together (the same schema can also include a `sparse_vector` field). A single search request ranks by one scoring type — multi-field BM25 is supported (multiple `text` clauses on different fields, or one `query_string` clause spanning fields), and any scoring method can be combined with metadata filters, including text-match filters (`$match_phrase`, `$match_all`, `$match_any`) on FTS-enabled `string` fields.
```bash curl theme={null}
curl -X POST "https://api.pinecone.io/indexes" \
-H "Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "X-Pinecone-Api-Version: 2026-01.alpha" \
-d '{
"name": "articles-multi",
"deployment": {
"deployment_type": "managed",
"cloud": "aws",
"region": "us-east-1"
},
"schema": {
"fields": {
"title": { "type": "string", "full_text_search": {} },
"body": { "type": "string", "full_text_search": {} },
"embedding":{ "type": "dense_vector", "dimension": 1536, "metric": "cosine" }
}
}
}'
```
You can include additional fields (for example, `category` or `year`) at upsert time. All metadata fields are automatically indexed for filtering — they don't need to be declared in the schema. The schema is for ranking fields only; declaring a metadata-only field (`string` without `full_text_search`, `string_list`, `float`, or `boolean`) is rejected at index creation.
For the full schema reference (all field types, language and analyzer options, dedicated read capacity, and Python SDK examples), see [Full-text search](/guides/search/full-text-search).
Schema migration is not yet supported. Once an index with a document schema is created, you cannot add, remove, or modify fields. Plan your schema carefully — if you need to change a schema, [delete the index](/guides/manage-data/manage-indexes#delete-an-index) and create a new one.
## Create an index for dense vectors
You can create an index that stores dense vectors with [integrated vector embedding](/guides/index-data/indexing-overview#integrated-embedding), or one that stores vectors generated with an external embedding model.
### Integrated embedding
Indexes with integrated embedding do not support [updating](/guides/manage-data/update-data) or [importing](/guides/index-data/import-data) with text.
If you want to upsert and search with source text and have Pinecone convert it to dense vectors automatically, [create an index with integrated embedding](/reference/api/latest/control-plane/create_for_model) as follows:
* Provide a `name` for the index.
* Set `cloud` and `region` to the [cloud and region](/guides/index-data/create-an-index#cloud-regions) where the index should be deployed.
* Set `embed.model` to one of [Pinecone's hosted embedding models](/guides/index-data/create-an-index#embedding-models).
* Set `embed.field_map` to the name of the field in your source document that contains the data for embedding.
Other parameters are optional. See the [API reference](/reference/api/latest/control-plane/create_for_model) for details.
```python Python theme={null}
from pinecone import Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
index_name = "integrated-dense-py"
if not pc.has_index(index_name):
pc.create_index_for_model(
name=index_name,
cloud="aws",
region="us-east-1",
embed={
"model":"llama-text-embed-v2",
"field_map":{"text": "chunk_text"}
}
)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' });
await pc.createIndexForModel({
name: 'integrated-dense-js',
cloud: 'aws',
region: 'us-east-1',
embed: {
model: 'llama-text-embed-v2',
fieldMap: { text: 'chunk_text' },
},
waitUntilReady: true,
});
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.ApiException;
import org.openapitools.db_control.client.model.CreateIndexForModelRequest;
import org.openapitools.db_control.client.model.CreateIndexForModelRequestEmbed;
import org.openapitools.db_control.client.model.DeletionProtection;
import java.util.HashMap;
import java.util.Map;
public class CreateIntegratedIndex {
public static void main(String[] args) throws ApiException {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
String indexName = "integrated-dense-java";
String region = "us-east-1";
HashMap fieldMap = new HashMap<>();
fieldMap.put("text", "chunk_text");
CreateIndexForModelRequestEmbed embed = new CreateIndexForModelRequestEmbed()
.model("llama-text-embed-v2")
.fieldMap(fieldMap);
Map tags = new HashMap<>();
tags.put("environment", "development");
pc.createIndexForModel(
indexName,
CreateIndexForModelRequest.CloudEnum.AWS,
region,
embed,
DeletionProtection.DISABLED,
tags
);
}
}
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
indexName := "integrated-dense-go"
deletionProtection := pinecone.DeletionProtectionDisabled
idx, err := pc.CreateIndexForModel(ctx, &pinecone.CreateIndexForModelRequest{
Name: indexName,
Cloud: pinecone.Aws,
Region: "us-east-1",
Embed: pinecone.CreateIndexForModelEmbed{
Model: "llama-text-embed-v2",
FieldMap: map[string]interface{}{"text": "chunk_text"},
},
DeletionProtection: &deletionProtection,
Tags: &pinecone.IndexTags{ "environment": "development" },
})
if err != nil {
log.Fatalf("Failed to create serverless integrated index: %v", idx.Name)
} else {
fmt.Printf("Successfully created serverless integrated index: %v", idx.Name)
}
}
```
```json curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -X POST "https://api.pinecone.io/indexes/create-for-model" \
-H "Content-Type: application/json" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"name": "integrated-dense-curl",
"cloud": "aws",
"region": "us-east-1",
"embed": {
"model": "llama-text-embed-v2",
"field_map": {
"text": "chunk_text"
}
}
}'
```
```bash CLI theme={null}
# Target the project where you want to create the index.
pc target -o "example-org" -p "example-project"
# Create the index.
pc index create \
--name "integrated-dense-cli" \
--metric "cosine" \
--cloud "aws" \
--region "us-east-1" \
--model "llama-text-embed-v2" \
--field_map "text=chunk_text" \
--tags "environment=development"
```
### Bring your own vectors
If you use an external embedding model to convert your data to dense vectors, [create an index](/reference/api/latest/control-plane/create_index) as follows:
* Provide a `name` for the index.
* Set the `vector_type` to `dense`.
* Specify the `dimension` and similarity `metric` of the vectors you'll store in the index. This should match the dimension and metric supported by your embedding model.
* Set `spec.cloud` and `spec.region` to the [cloud and region](/guides/index-data/create-an-index#cloud-regions) where the index should be deployed. For Python, you also need to import the `ServerlessSpec` class.
Other parameters are optional. See the [API reference](/reference/api/latest/control-plane/create_index) for details.
```python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
from pinecone import ServerlessSpec
pc = Pinecone(api_key="YOUR_API_KEY")
index_name = "standard-dense-py"
if not pc.has_index(index_name):
pc.create_index(
name=index_name,
vector_type="dense",
dimension=1536,
metric="cosine",
spec=ServerlessSpec(
cloud="aws",
region="us-east-1"
),
deletion_protection="disabled",
tags={
"environment": "development"
}
)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' });
await pc.createIndex({
name: 'standard-dense-js',
vectorType: 'dense',
dimension: 1536,
metric: 'cosine',
spec: {
serverless: {
cloud: 'aws',
region: 'us-east-1'
}
},
deletionProtection: 'disabled',
tags: { environment: 'development' },
});
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.model.IndexModel;
import org.openapitools.db_control.client.model.DeletionProtection;
import java.util.HashMap;
public class CreateServerlessIndexExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
String indexName = "standard-dense-java";
String cloud = "aws";
String region = "us-east-1";
String vectorType = "dense";
Map tags = new HashMap<>();
tags.put("environment", "development");
pc.createServerlessIndex(
indexName,
"cosine",
1536,
cloud,
region,
DeletionProtection.DISABLED,
tags,
vectorType
);
}
}
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
// Serverless index
indexName := "standard-dense-go"
vectorType := "dense"
dimension := int32(1536)
metric := pinecone.Cosine
deletionProtection := pinecone.DeletionProtectionDisabled
idx, err := pc.CreateServerlessIndex(ctx, &pinecone.CreateServerlessIndexRequest{
Name: indexName,
VectorType: &vectorType,
Dimension: &dimension,
Metric: &metric,
Cloud: pinecone.Aws,
Region: "us-east-1",
DeletionProtection: &deletionProtection,
Tags: &pinecone.IndexTags{ "environment": "development" },
})
if err != nil {
log.Fatalf("Failed to create serverless index: %v", err)
} else {
fmt.Printf("Successfully created serverless index: %v", idx.Name)
}
}
```
```shell curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -X POST "https://api.pinecone.io/indexes" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"name": "standard-dense-curl",
"vector_type": "dense",
"dimension": 1536,
"metric": "cosine",
"spec": {
"serverless": {
"cloud": "aws",
"region": "us-east-1"
}
},
"tags": {
"environment": "development"
},
"deletion_protection": "disabled"
}'
```
```bash CLI theme={null}
# Target the project where you want to create the index.
pc target -o "example-org" -p "example-project"
# Create the index.
pc index create \
--name "standard-dense-cli" \
--vector_type "dense" \
--dimension 1536 \
--metric "cosine" \
--cloud "aws" \
--region "us-east-1" \
--tags "environment=development" \
--deletion_protection "disabled"
```
## Create an index for sparse vectors
You can create an index that stores sparse vectors with [integrated vector embedding](/guides/index-data/indexing-overview#integrated-embedding), or one that stores vectors generated with an external embedding model.
### Integrated embedding
If you want to upsert and search with source text and have Pinecone convert it to sparse vectors automatically, [create an index with integrated embedding](/reference/api/latest/control-plane/create_for_model) as follows:
* Provide a `name` for the index.
* Set `cloud` and `region` to the [cloud and region](/guides/index-data/create-an-index#cloud-regions) where the index should be deployed.
* Set `embed.model` to one of [Pinecone's hosted sparse embedding models](/guides/index-data/create-an-index#embedding-models).
* Set `embed.field_map` to the name of the field in your source document that contains the text for embedding.
* If needed, `embed.read_parameters` and `embed.write_parameters` can be used to override the default model embedding behavior.
Other parameters are optional. See the [API reference](/reference/api/latest/control-plane/create_for_model) for details.
```python Python theme={null}
from pinecone import Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
index_name = "integrated-sparse-py"
if not pc.has_index(index_name):
pc.create_index_for_model(
name=index_name,
cloud="aws",
region="us-east-1",
embed={
"model":"pinecone-sparse-english-v0",
"field_map":{"text": "chunk_text"}
}
)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' });
await pc.createIndexForModel({
name: 'integrated-sparse-js',
cloud: 'aws',
region: 'us-east-1',
embed: {
model: 'pinecone-sparse-english-v0',
fieldMap: { text: 'chunk_text' },
},
waitUntilReady: true,
});
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.ApiException;
import org.openapitools.db_control.client.model.CreateIndexForModelRequest;
import org.openapitools.db_control.client.model.CreateIndexForModelRequestEmbed;
import org.openapitools.db_control.client.model.DeletionProtection;
import java.util.HashMap;
import java.util.Map;
public class CreateIntegratedIndex {
public static void main(String[] args) throws ApiException {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
String indexName = "integrated-sparse-java";
String region = "us-east-1";
HashMap fieldMap = new HashMap<>();
fieldMap.put("text", "chunk_text");
CreateIndexForModelRequestEmbed embed = new CreateIndexForModelRequestEmbed()
.model("pinecone-sparse-english-v0")
.fieldMap(fieldMap);
Map tags = new HashMap<>();
tags.put("environment", "development");
pc.createIndexForModel(
indexName,
CreateIndexForModelRequest.CloudEnum.AWS,
region,
embed,
DeletionProtection.DISABLED,
tags
);
}
}
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
indexName := "integrated-sparse-go"
deletionProtection := pinecone.DeletionProtectionDisabled
idx, err := pc.CreateIndexForModel(ctx, &pinecone.CreateIndexForModelRequest{
Name: indexName,
Cloud: pinecone.Aws,
Region: "us-east-1",
Embed: pinecone.CreateIndexForModelEmbed{
Model: "pinecone-sparse-english-v0",
FieldMap: map[string]interface{}{"text": "chunk_text"},
},
DeletionProtection: &deletionProtection,
Tags: &pinecone.IndexTags{ "environment": "development" },
})
if err != nil {
log.Fatalf("Failed to create serverless integrated index: %v", idx.Name)
} else {
fmt.Printf("Successfully created serverless integrated index: %v", idx.Name)
}
}
```
```shell curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -X POST "https://api.pinecone.io/indexes/create-for-model" \
-H "Content-Type: application/json" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"name": "integrated-sparse-curl",
"cloud": "aws",
"region": "us-east-1",
"embed": {
"model": "pinecone-sparse-english-v0",
"field_map": {
"text": "chunk_text"
}
}
}'
```
```bash CLI theme={null}
# Target the project where you want to create the index.
pc target -o "example-org" -p "example-project"
# Create the index.
pc index create \
--name "integrated-sparse-cli" \
--cloud "aws" \
--region "us-east-1" \
--model "pinecone-sparse-english-v0" \
--field_map "text=chunk_text" \
--tags "environment=development"
```
### Bring your own vectors
If you use an external embedding model to convert your data to sparse vectors, [create an index](/reference/api/latest/control-plane/create_index) as follows:
* Provide a `name` for the index.
* Set the `vector_type` to `sparse`.
* Set the distance `metric` to `dotproduct`. Indexes that store sparse vectors do not support other [distance metrics](/guides/index-data/indexing-overview#distance-metrics).
* Set `spec.cloud` and `spec.region` to the cloud and region where the index should be deployed.
Other parameters are optional. See the [API reference](/reference/api/latest/control-plane/create_index) for details.
```python Python theme={null}
from pinecone import Pinecone, ServerlessSpec
pc = Pinecone(api_key="YOUR_API_KEY")
index_name = "standard-sparse-py"
if not pc.has_index(index_name):
pc.create_index(
name=index_name,
vector_type="sparse",
metric="dotproduct",
spec=ServerlessSpec(cloud="aws", region="us-east-1")
)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' });
await pc.createIndex({
name: 'standard-sparse-js',
vectorType: 'sparse',
metric: 'dotproduct',
spec: {
serverless: {
cloud: 'aws',
region: 'us-east-1'
},
},
});
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.model.DeletionProtection;
import java.util.*;
public class SparseIndex {
public static void main(String[] args) throws InterruptedException {
// Instantiate Pinecone class
Pinecone pinecone = new Pinecone.Builder("YOUR_API_KEY").build();
// Create the index
String indexName = "standard-sparse-java";
String cloud = "aws";
String region = "us-east-1";
String vectorType = "sparse";
Map tags = new HashMap<>();
tags.put("env", "test");
pinecone.createSparseServelessIndex(indexName,
cloud,
region,
DeletionProtection.DISABLED,
tags,
vectorType);
}
}
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
indexName := "standard-sparse-go"
vectorType := "sparse"
metric := pinecone.Dotproduct
deletionProtection := pinecone.DeletionProtectionDisabled
idx, err := pc.CreateServerlessIndex(ctx, &pinecone.CreateServerlessIndexRequest{
Name: indexName,
Metric: &metric,
VectorType: &vectorType,
Cloud: pinecone.Aws,
Region: "us-east-1",
DeletionProtection: &deletionProtection,
})
if err != nil {
log.Fatalf("Failed to create serverless index: %v", err)
} else {
fmt.Printf("Successfully created serverless index: %v", idx.Name)
}
}
```
```shell curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -X POST "https://api.pinecone.io/indexes" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"name": "standard-sparse-curl",
"vector_type": "sparse",
"metric": "dotproduct",
"spec": {
"serverless": {
"cloud": "aws",
"region": "us-east-1"
}
}
}'
```
```bash CLI theme={null}
# Target the project where you want to create the index.
pc target -o "example-org" -p "example-project"
# Create the index.
pc index create \
--name "standard-sparse-cli" \
--vector_type "sparse" \
--metric "dotproduct" \
--cloud "aws" \
--region "us-east-1" \
--tags "environment=development"
```
## Create an index from a backup
You can restore an index from a backup, regardless of whether it stores dense or sparse vectors. For more details, see [Restore an index](/guides/manage-data/restore-an-index).
## Metadata indexing
This feature is in [early access](/release-notes/feature-availability) and available only on the `2025-10` version of the API. The CLI does not yet support this feature.
Pinecone indexes all metadata fields by default. However, large amounts of metadata can cause slower [index building](/guides/get-started/database-architecture#index-builder) as well as slower [query execution](/guides/get-started/database-architecture#query-executors), particularly when data is not cached in a query executor's memory and local SSD and must be fetched from object storage.
To prevent performance issues due to excessive metadata, you can limit metadata indexing to the fields that you plan to use for [query filtering](/guides/search/filter-by-metadata).
### Set metadata indexing
You can set metadata indexing during index creation or [namespace creation](/reference/api/2025-10/data-plane/createnamespace):
* Index-level metadata indexing rules apply to all namespaces that don't have explicit metadata indexing rules.
* Namespace-level metadata indexing rules overrides index-level metadata indexing rules.
For example, let's say you want to store records that represent chunks of a document, with each record containing many metadata fields. Since you plan to use only a few of the metadata fields to filter queries, you would specify the metadata fields to index as follows.
Metadata indexing cannot be changed after index or namespace creation.
```shell Index-level metadata indexing theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl "https://api.pinecone.io/indexes" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"name": "example-index-metadata",
"vector_type": "dense",
"dimension": 1536,
"metric": "cosine",
"spec": {
"serverless": {
"cloud": "aws",
"region": "us-east-1",
"schema": {
"fields": {
"document_id": {
"filterable": true
},
"document_title": {
"filterable": true
},
"chunk_number": {
"filterable": true
},
"document_url": {
"filterable": true
},
"created_at": {
"filterable": true
}
}
}
}
},
"deletion_protection": "disabled"
}'
```
```shell Namespace-level metadata indexing theme={null}
# To learn how to get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
curl "https://$INDEX_HOST/namespaces" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"name": "example-namespace",
"schema": {
"fields": {
"document_id": {
"filterable": true
},
"document_title": {
"filterable": true
},
"chunk_number": {
"filterable": true
},
"document_url": {
"filterable": true
},
"created_at": {
"filterable": true
}
}
}
}'
```
### Check metadata indexing
To check which metadata fields are indexed, you can describe the index or namespace:
```shell Describe index theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -X GET "https://api.pinecone.io/indexes/example-index-metadata" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10"
```
```shell Describe namespace theme={null}
# To learn how to get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
curl -X GET "https://$INDEX_HOST/namespaces/example-namespace" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10"
```
The response includes the `schema` object with the names of the metadata fields explicitly indexed during index or namespace creation.
The response does not include unindexed metadata fields or metadata fields indexed by default.
```json Describe index theme={null}
{
"id": "751ab850-6e61-4f92-bd23-fa129803d207",
"vector_type": "dense",
"name": "example-index",
"metric": "cosine",
"dimension": 1536,
"status": {
"ready": false,
"state": "Initializing"
},
"host": "example-index-fa77d8e.svc.aped-4627-b74a.pinecone.io",
"spec": {
"serverless": {
"region": "us-east-1",
"cloud": "aws",
"read_capacity": {
"mode": "OnDemand",
"status": "Ready"
},
"schema": {
"fields": {
"document_id": {
"filterable": true
},
"document_title": {
"filterable": true
},
"created_at": {
"filterable": true
},
"chunk_number": {
"filterable": true
},
"document_url": {
"filterable": true
}
}
}
}
},
"deletion_protection": "disabled",
"tags": null
}
```
```json Describe namespace theme={null}
{
"name": "example-namespace",
"record_count": "20000",
"schema": {
"fields": {
"document_title": {
"filterable": true
},
"document_url": {
"filterable": true
},
"chunk_number": {
"filterable": true
},
"document_id": {
"filterable": true
},
"created_at": {
"filterable": true
}
}
}
}
```
## Index options
### Cloud regions
When creating an index, you must choose the cloud and region where you want the index to be hosted. The following table lists the available public clouds and regions and the plans that support them:
| Cloud | Region | [Supported plans](https://www.pinecone.io/pricing/) | [Availability phase](/release-notes/feature-availability) |
| ------- | ---------------------------- | --------------------------------------------------- | --------------------------------------------------------- |
| `aws` | `us-east-1` (Virginia) | Starter, Builder, Standard, Enterprise | General availability |
| `aws` | `us-west-2` (Oregon) | Builder, Standard, Enterprise | General availability |
| `aws` | `eu-west-1` (Ireland) | Builder, Standard, Enterprise | General availability |
| `aws` | `eu-central-1` (Frankfurt) | Builder, Standard, Enterprise | General availability |
| `aws` | `ap-southeast-1` (Singapore) | Builder, Standard, Enterprise | General availability |
| `gcp` | `us-central1` (Iowa) | Builder, Standard, Enterprise | General availability |
| `gcp` | `europe-west4` (Netherlands) | Builder, Standard, Enterprise | General availability |
| `azure` | `eastus2` (Virginia) | Builder, Standard, Enterprise | General availability |
The cloud and region cannot be changed after a serverless index is created.
On the Starter plan, you can create serverless indexes in the `us-east-1` region of AWS only. To create indexes in other regions, [upgrade to the Builder, Standard, or Enterprise plan](/guides/organizations/manage-billing/upgrade-billing-plan).
### Similarity metrics
When creating an index that stores dense vectors, you can choose from the following similarity metrics. For the most accurate results, choose the similarity metric used to train the embedding model for your vectors. For more information, see [Vector Similarity Explained](https://www.pinecone.io/learn/vector-similarity/).
Indexes that store [sparse vectors](#sparse-indexes) must use the `dotproduct` metric.
Querying indexes with this metric returns a similarity score equal to the squared Euclidean distance between the result and query vectors.
This metric calculates the square of the distance between two data points in a plane. It is one of the most commonly used distance metrics. For an example, see our [IT threat detection example](https://colab.research.google.com/github/pinecone-io/examples/blob/master/docs/it-threat-detection.ipynb).
When you use `metric='euclidean'`, the most similar results are those with the **lowest similarity score**.
This is often used to find similarities between different documents. The advantage is that the scores are normalized to \[-1,1] range. For an example, see our [generative question answering example](https://colab.research.google.com/github/pinecone-io/examples/blob/master/docs/gen-qa-openai.ipynb).
This is used to multiply two vectors. You can use it to tell us how similar the two vectors are. The more positive the answer is, the closer the two vectors are in terms of their directions. For an example, see our [semantic search example](https://colab.research.google.com/github/pinecone-io/examples/blob/master/docs/semantic-search.ipynb).
### Embedding models
[Dense vectors](/guides/get-started/concepts#dense-vector) and [sparse vectors](/guides/get-started/concepts#sparse-vector) are the basic units of data in Pinecone and what Pinecone was specially designed to store and work with. Dense vectors represents the semantics of data such as text, images, and audio recordings, while sparse vectors represent documents or queries in a way that captures keyword information.
To transform data into vector format, you use an embedding model. Pinecone hosts several embedding models so it's easy to manage your vector storage and search process on a single platform. You can use a hosted model to embed your data as an integrated part of upserting and querying, or you can use a hosted model to embed your data as a standalone operation.
The following embedding models are hosted by Pinecone.
To understand how cost is calculated for embedding, see [Embedding cost](/guides/manage-cost/understanding-cost#embedding). To get model details via the API, see [List models](/reference/api/latest/inference/list_models) and [Describe a model](/reference/api/latest/inference/describe_model).
#### multilingual-e5-large
[`multilingual-e5-large`](/models/multilingual-e5-large) is an efficient dense embedding model trained on a mixture of multilingual datasets. It works well on messy data and short queries expected to return medium-length passages of text (1-2 paragraphs).
**Details**
* Vector type: Dense
* Modality: Text
* Dimension: 1024
* Recommended similarity metric: Cosine
* Max sequence length: 507 tokens
* Max batch size: 96 sequences
For rate limits, see [Embedding tokens per minute](/reference/api/database-limits#embedding-tokens-per-minute-per-model) and [Embedding tokens per month](/reference/api/database-limits#embedding-tokens-per-month-per-model).
**Parameters**
The `multilingual-e5-large` model supports the following parameters:
| Parameter | Type | Required/Optional | Description | Default |
| :----------- | :----- | :---------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------ |
| `input_type` | string | Required | The type of input data. Accepted values: `query` or `passage`. | |
| `truncate` | string | Optional | How to handle inputs longer than those supported by the model. Accepted values: `END` or `NONE`.
`END` truncates the input sequence at the input token limit. `NONE` returns an error when the input exceeds the input token limit. | `END` |
#### llama-text-embed-v2
[`llama-text-embed-v2`](/models/llama-text-embed-v2) is a high-performance dense embedding model optimized for text retrieval and ranking tasks. It is trained on a diverse range of text corpora and provides strong performance on longer passages and structured documents.
**Details**
* Vector type: Dense
* Modality: Text
* Dimension: 1024 (default), 2048, 768, 512, 384
* Recommended similarity metric: Cosine
* Max sequence length: 2048 tokens
* Max batch size: 96 sequences
For rate limits, see [Embedding tokens per minute](/reference/api/database-limits#embedding-tokens-per-minute-per-model) and [Embedding tokens per month](/reference/api/database-limits#embedding-tokens-per-month-per-model).
**Parameters**
The `llama-text-embed-v2` model supports the following parameters:
| Parameter | Type | Required/Optional | Description | Default |
| :----------- | :------ | :---------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------ |
| `input_type` | string | Required | The type of input data. Accepted values: `query` or `passage`. | |
| `truncate` | string | Optional | How to handle inputs longer than those supported by the model. Accepted values: `END` or `NONE`.
`END` truncates the input sequence at the input token limit. `NONE` returns an error when the input exceeds the input token limit. | `END` |
| `dimension` | integer | Optional | Dimension of the vector to return. | 1024 |
#### pinecone-sparse-english-v0
[`pinecone-sparse-english-v0`](/models/pinecone-sparse-english-v0) is a sparse embedding model for converting text to [sparse vectors](/guides/get-started/concepts#sparse-vector) for [sparse-vector lexical search](/guides/search/lexical-search) or hybrid search. Built on the innovations of the [DeepImpact architecture](https://arxiv.org/pdf/2104.12016), the model directly estimates the lexical importance of tokens by leveraging their context, unlike traditional retrieval models like BM25, which rely solely on term frequency.
**Details**
* Vector type: Sparse
* Modality: Text
* Recommended similarity metric: Dotproduct
* Max sequence length: 512 or 2048
* Max batch size: 96 sequences
For rate limits, see [Embedding tokens per minute](/reference/api/database-limits#embedding-tokens-per-minute-per-model) and [Embedding tokens per month](/reference/api/database-limits#embedding-tokens-per-month-per-model).
**Parameters**
The `pinecone-sparse-english-v0` model supports the following parameters:
| Parameter | Type | Required/Optional | Description | Default |
| :------------------------ | :------ | :---------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------ |
| `input_type` | string | Required | The type of input data. Accepted values: `query` or `passage`. | |
| `max_tokens_per_sequence` | integer | Optional | Maximum number of tokens to embed. Accepted values: `512` or `2048`. | `512` |
| `truncate` | string | Optional | How to handle inputs longer than those supported by the model. Accepted values: `END` or `NONE`.
`END` truncates the input sequence at the the `max_tokens_per_sequence` limit. `NONE` returns an error when the input exceeds the `max_tokens_per_sequence` limit. | `END` |
| `return_tokens` | boolean | Optional | Whether to return the string tokens. | `false` |
# Data ingestion overview
Source: https://docs.pinecone.io/guides/index-data/data-ingestion-overview
Compare data ingestion options in Pinecone: bulk import from object storage, upsert operations, and hosted embedding via the Inference API.
To control costs when ingesting large datasets (10,000,000+ records), use [import](/guides/index-data/import-data) instead of upsert.
## Import from object storage
[Importing from object storage](/guides/index-data/import-data) is the most efficient and cost-effective method to load large numbers of records into an index. You store your data as Parquet files in object storage, integrate your object storage with Pinecone, and then start an asynchronous, long-running operation that imports and indexes your records.
This feature is in [public preview](/release-notes/feature-availability) and available only on [Standard and Enterprise plans](https://www.pinecone.io/pricing/).
## Upsert
For ongoing ingestion into an index, either one record at a time or in batches, use the [upsert](/guides/index-data/upsert-data) operation. [Batch upserting](/guides/index-data/upsert-data#upsert-in-batches) can improve throughput performance and is a good option for larger numbers of records if you cannot work around import's current [limitations](/guides/index-data/import-data#import-limits).
## When you only need embeddings
Import and upsert move vectors into Pinecone. For workflows where you only need vectors from hosted models (for example, to embed offline and upsert later), use the Inference API as follows:
You can call the [`embed` operation](/reference/api/latest/inference/generate-embeddings) through Pinecone Inference to turn text into vectors without writing to an index. That differs from [`upsert_records`](/reference/api/latest/data-plane/upsert_records) on an index with integrated embedding, where each request embeds and stores records in one step. To see how embedding consumption appears in billing and usage reports, see [Embedding tokens](/guides/manage-cost/monitor-usage-and-costs#embedding-tokens).
## Ingestion cost
* To understand how cost is calculated for imports, see [Import cost](/guides/manage-cost/understanding-cost#imports).
* To understand how cost is calculated for upserts, see [Write unit pricing](/guides/manage-cost/understanding-cost#write-units).
* For up-to-date pricing information, see [Pricing](https://www.pinecone.io/pricing/).
## Data freshness
Pinecone is eventually consistent, so there can be a slight delay before new or changed records are visible to queries. You can view index stats to [check data freshness](/guides/index-data/check-data-freshness).
# Data modeling
Source: https://docs.pinecone.io/guides/index-data/data-modeling
Model your data in Pinecone using documents with dense_vector, sparse_vector, full-text string, and metadata fields for efficient retrieval.
Pinecone has two ways to model your data, and the choice is made when you create the index: an index created with a document schema holds documents, while an index created with a dense or sparse vector type holds records. Both hold a unique `_id` and optional metadata and live in [namespaces](/guides/index-data/indexing-overview#namespaces); they differ in how many ranking signals a single item can carry and which API you call. Both are fully supported.
* **[Documents](#documents)** are the unit of data in an index with a **document schema**, the model behind [full-text search](/guides/search/full-text-search). A document is a JSON object that can carry text fields (ranked with BM25 and Lucene queries), a dense vector, a sparse vector, and metadata in a single index, and you pick the ranking signal per query with `score_by`. Use documents for text-first search or any workload that needs more than one ranking signal in one index.
* **[Records](#records)** are the unit of data for [indexes with dense vectors](/guides/get-started/concepts#index-with-dense-vectors) and [indexes with sparse vectors](/guides/get-started/concepts#index-with-sparse-vectors), the vector API. A record carries one vector (or raw text for Pinecone to embed) plus metadata. Use records for vector-only workloads.
## Documents
A document is the unit of data in an index with a document schema — a JSON object with a required `_id` field, the ranking fields declared in the index's schema, and any number of metadata fields. Documents support multiple field types in a single record: a `dense_vector` field (for [semantic search](/guides/search/semantic-search)), a `sparse_vector` field (for [sparse-vector lexical search](/guides/search/lexical-search)), one or more `string` fields with `full_text_search` enabled (for [full-text search](/guides/search/full-text-search) with BM25 and Lucene queries), plus any metadata you upsert alongside them.
The schema, declared at index creation, tells Pinecone how to rank each ranking field. Schema field types:
* `dense_vector` — indexed for ANN similarity search.
* `sparse_vector` — indexed for sparse-vector lexical search.
* `string` with a nested `full_text_search` config object (`{}` enables with all defaults; optional sub-fields: `language`, `stemming`, `stop_words`) — indexed for **BM25** ranking and Lucene queries. Lowercasing and the token length cap are server-applied and cannot be overridden.
Metadata fields are not declared in the schema. Any field you upsert that is not declared in the schema is stored on the document, returned via `include_fields`, and automatically indexed for filtering. Pinecone infers the metadata field type from the values you upsert: strings, numbers (floating point), booleans, and arrays of strings are all supported.
Document fields can hold structured values: a metadata `string_list` field holds an array of strings; a `dense_vector` field holds an array of floats; a `sparse_vector` field is an object with two parallel arrays — `indices` (token positions) and `values` (token weights).
A schema can declare up to 100 `string` fields with `full_text_search` enabled, but at most one `dense_vector` field and at most one `sparse_vector` field per index.
Example document for an index with `title`, `body`, `embedding`, and `category` fields:
```json theme={null}
{
"_id": "document1#chunk1",
"title": "Introduction to Vector Databases",
"body": "First chunk of the document content...",
"embedding": [0.0236, -0.0329, ..., -0.0104, 0.0086],
"category": "tutorial"
}
```
Field-name rules:
* Must be unique, non-empty strings.
* Must not start with `_` (reserved for system-managed fields like `_id` and `_score`) or `$` (reserved for filter operators).
* Limited to 64 bytes.
For the full schema reference (language and analyzer options, multi-field schemas, scoring methods), see [Full-text search](/guides/search/full-text-search).
**Chunking granularity.** A document is the unit of retrieval — `top_k` and `_score` are computed per document, not per sub-section. In public preview, Pinecone does not split a single document into multiple in-document chunks at index time. If your source content is longer than what you want to retrieve as one hit (a long article, a PDF, a transcript), do the chunking in your application before upsert and store each chunk as its own document, with an ID like `document1#chunk1`, `document1#chunk2`, and a metadata field that ties chunks back to the parent document for grouping at query time.
### Schema patterns
The same document model supports several common schema shapes. Pick the one that matches the signal you want to rank by, and plan your fields up front: in public preview, schema migration is not supported after index creation. Filters are deterministic per document and apply before scoring; choose your hard yes/no constraints (including text-match operators on FTS-enabled `string` fields) first, then pick a `score_by` method to rank whatever remains. See [Filters vs. scoring](/guides/search/full-text-search#filters-vs-scoring).
The Python snippets in each accordion below assume an initialized client and the schema-builder import:
```python Python theme={null}
from pinecone import Pinecone
from pinecone.preview import SchemaBuilder
pc = Pinecone(api_key="YOUR_API_KEY")
```
Each accordion shows the pattern-specific schema, an example document, and a search snippet. The control-plane (`pc.preview.indexes.create(...)`) and data-plane (`index = pc.preview.index(name=...)`) calls in the snippets reuse this `pc`.
Use when you want BM25 keyword ranking on one piece of text per document (a review body, a support ticket, a product description) and you don't have embeddings to manage.
```python Python theme={null}
from pinecone.preview import SchemaBuilder
schema = (
SchemaBuilder()
.add_string_field("review_text", full_text_search={"language": "en"})
.build()
)
pc.preview.indexes.create(name="book-reviews", schema=schema)
```
A document upserted into this index looks like:
```json theme={null}
{
"_id": "review-1234",
"review_text": "Beautifully written exploration of contact, communication, and civilization across cosmic distances. The pacing is uneven but the central premise carries you through."
}
```
Search with a single `text` clause (the score\_by `type`, not a field type — this clause runs BM25 ranking on the named string field):
```python Python theme={null}
index.documents.search(
namespace="reviews",
top_k=10,
score_by=[{"type": "text", "field": "review_text", "query": "civilization"}],
)
```
See [Full-text search](/guides/search/full-text-search).
Use when a document has more than one piece of text that should both contribute to ranking — for example, a long `review_text` plus a short `review_summary`. Pinecone combines the per-field BM25 scores into one ranking per document.
```python Python theme={null}
schema = (
SchemaBuilder()
.add_string_field("review_text", full_text_search={"language": "en"})
.add_string_field("review_summary", full_text_search={"language": "en"})
.build()
)
pc.preview.indexes.create(name="book-reviews-multi", schema=schema)
```
A document upserted into this index looks like:
```json theme={null}
{
"_id": "review-1234",
"review_text": "Beautifully written exploration of contact, communication, and civilization across cosmic distances. The pacing is uneven but the central premise carries you through.",
"review_summary": "Monumental science fiction with uneven pacing",
"category": "science-fiction",
"rating": 4.5
}
```
`category` and `rating` are not declared in the schema — they're upserted as metadata, automatically indexed for filtering, and usable in `filter` expressions.
Pass two `text` clauses in `score_by`; the server combines them into one ranking, with each contributing field weighted equally in `2026-01.alpha`.
```python Python theme={null}
index = pc.preview.index(name="book-reviews-multi")
index.documents.search(
namespace="reviews",
top_k=5,
score_by=[
{"type": "text", "field": "review_text", "query": "disappointing"},
{"type": "text", "field": "review_summary", "query": "Disappointing"},
],
include_fields=["*"],
)
```
Most workloads that combine semantic ranking with keyword matching reach for this pattern: rank by dense (or sparse) similarity, restricted to documents that contain a specific term or phrase. Common examples include semantic search over patents, regulatory filings, internal knowledge bases, or other technical literature where the right answer must contain a specific term. A single schema can include one `dense_vector` field plus any number of FTS-enabled string fields:
```python Python theme={null}
schema = (
SchemaBuilder()
.add_string_field("book_title", full_text_search={"language": "en"})
.add_string_field("review_text", full_text_search={"language": "en"})
.add_dense_vector_field("review_embedding", dimension=1024, metric="cosine")
.build()
)
pc.preview.indexes.create(name="book-reviews-dense", schema=schema)
```
A document upserted into this index looks like:
```json theme={null}
{
"_id": "review-1234",
"book_title": "The Three-Body Problem",
"review_text": "Beautifully written exploration of contact, communication, and civilization across cosmic distances.",
"review_embedding": [0.012, -0.087, 0.153, ...]
}
```
`review_embedding` is a 1024-dim list of floats produced by your dense embedding model. Use the same model at query time so the query vector lives in the same space.
A single search request ranks by one scoring type. With this schema you have two query options:
**Option A — dense ranking restricted by a text-match filter** (the most common hybrid pattern):
```python Python theme={null}
index = pc.preview.index(name="book-reviews-dense")
# query_embedding is a 1024-dim list of floats from your embedding model.
query_embedding = embed("beautifully written, hard sci-fi")
index.documents.search(
namespace="reviews",
top_k=5,
score_by=[
{"type": "dense_vector", "field": "review_embedding", "values": query_embedding},
],
filter={"review_text": {"$match_phrase": "beautifully written"}},
)
```
**Option B — run BM25 and dense searches separately and merge client-side** (when you want both signals to contribute to ranking, e.g. via [reciprocal rank fusion](/guides/search/reciprocal-rank-fusion)):
```python Python theme={null}
dense_hits = index.documents.search(
namespace="reviews", top_k=50,
score_by=[{"type": "dense_vector", "field": "review_embedding", "values": query_embedding}],
)
bm25_hits = index.documents.search(
namespace="reviews", top_k=50,
score_by=[{"type": "text", "field": "review_text", "query": "beautifully written"}],
)
# Merge dense_hits + bm25_hits in your application (e.g. RRF) to produce final ranking.
```
See [Hybrid search](/guides/search/hybrid-search) for a fuller discussion.
The `dense_vector` field's source content is independent of the FTS-enabled `string` fields it sits alongside. You can embed images (e.g., with a multimodal model like Gemini Embedding 2 or a CLIP-style model) and pair them with FTS-enabled `string` fields holding captions, geography, or taxonomy — then query the image vector with a text description and restrict matches with FTS filters on those `string` fields. The schema doesn't constrain what the dense vector represents; it just stores a vector of the declared dimension.
Use when a single document is best described by more than one ranking signal — for example, a video catalog where each item has frame embeddings (dense), auto-generated captions you've encoded as sparse vectors (sparse), and a transcript text field (BM25/Lucene). One schema declares all three; you pick the ranking signal per query with `score_by`. No second index, no cross-index linkage to maintain.
```python Python theme={null}
schema = (
SchemaBuilder()
.add_dense_vector_field("frame_embedding", dimension=1024, metric="cosine")
.add_sparse_vector_field("caption_sparse")
.add_string_field("transcript", full_text_search={"language": "en"})
.build()
)
pc.preview.indexes.create(name="video-catalog", schema=schema)
```
A `language` field upserted alongside these ranking fields is treated as metadata: stored on the document, returned via `include_fields`, and auto-indexed for filtering.
A document upserted into this index looks like:
```json theme={null}
{
"_id": "video-7890#scene-3",
"frame_embedding": [0.012, -0.087, 0.153, ...],
"caption_sparse": {
"indices": [42, 1077, 9821],
"values": [0.41, 0.33, 0.18]
},
"transcript": "I think we should go now before it gets dark.",
"language": "en"
}
```
`frame_embedding` is a 1024-dim list of floats from your dense vision model. `caption_sparse` is the output of your sparse encoder — an object with parallel `indices` (token IDs) and `values` (token weights) arrays.
The same index supports three different query shapes. All three assume:
```python Python theme={null}
index = pc.preview.index(name="video-catalog")
# Replace with the outputs of your encoders.
query_embedding = embed_image(query_image) # 1024-dim list of floats
query_sparse = sparse_encode("scene with a lighthouse") # {"indices": [...], "values": [...]}
```
**Semantic frame search** — rank by visual similarity:
```python Python theme={null}
index.documents.search(
namespace="videos",
top_k=10,
score_by=[{"type": "dense_vector", "field": "frame_embedding", "values": query_embedding}],
)
```
**Caption lexical search** — rank by sparse-vector lexical similarity over your encoded captions:
```python Python theme={null}
index.documents.search(
namespace="videos",
top_k=10,
score_by=[{"type": "sparse_vector", "field": "caption_sparse", "sparse_values": query_sparse}],
)
```
**Semantic search restricted to spoken phrase** — semantic frame ranking, narrowed to clips where the transcript contains a specific phrase:
```python Python theme={null}
index.documents.search(
namespace="videos",
top_k=10,
score_by=[{"type": "dense_vector", "field": "frame_embedding", "values": query_embedding}],
filter={"transcript": {"$match_phrase": "I love you"}},
)
```
`score_by` selects one ranking signal per request, but every signal stays addressable on the same documents.
Use when you're modeling data with the [vector API](#records) (not the document API) and want to combine a sparse and dense vector in one record on a single index. For new document-centric projects with text data, prefer the document-shape Dense + FTS pattern above.
```json theme={null}
{
"id": "doc1#chunk1",
"values": [0.0236, -0.0329, ..., -0.0104, 0.0086],
"sparse_values": {
"indices": [822745112, 1009084850, ...],
"values": [1.7958984, 0.41577148, ...]
},
"metadata": { "document_id": "doc1", "chunk_number": 1 }
}
```
See [Hybrid search](/guides/search/hybrid-search).
## Records
Records are how you model data for [indexes with dense vectors](/guides/get-started/concepts#index-with-dense-vectors) and [indexes with sparse vectors](/guides/get-started/concepts#index-with-sparse-vectors). Each record carries one vector (dense, sparse, or both for single-index hybrid) plus optional metadata, and you can upsert raw text in place of a vector when the index is [integrated with an embedding model](/guides/index-data/create-an-index#embedding-models).
When you upsert pre-generated vectors, each record consists of the following:
* **ID**: A unique string identifier for the record.
* **Vector**: A dense vector for [semantic search](/guides/search/semantic-search), a sparse vector for [sparse-vector lexical search](/guides/search/lexical-search), or both for single-index [hybrid search](/guides/search/hybrid-search) (vector API).
* **Metadata** (optional): A flat JSON document containing key-value pairs with additional information (nested objects are not supported). You can filter by metadata when searching or deleting records.
When importing data from object storage, records must be in Parquet format. For more details, see [Import data](/guides/index-data/import-data#prepare-your-data).
Example:
```json Dense theme={null}
{
"id": "document1#chunk1",
"values": [0.0236663818359375, -0.032989501953125, ..., -0.01041412353515625, 0.0086669921875],
"metadata": {
"document_id": "document1",
"document_title": "Introduction to Vector Databases",
"chunk_number": 1,
"chunk_text": "First chunk of the document content...",
"document_url": "https://example.com/docs/document1",
"created_at": "2024-01-15",
"document_type": "tutorial"
}
}
```
```json Sparse theme={null}
{
"id": "document1#chunk1",
"sparse_values": {
"values": [1.7958984, 0.41577148, ..., 4.4414062, 3.3554688],
"indices": [822745112, 1009084850, ..., 3517203014, 3590924191]
},
"metadata": {
"document_id": "document1",
"document_title": "Introduction to Vector Databases",
"chunk_number": 1,
"chunk_text": "First chunk of the document content...",
"document_url": "https://example.com/docs/document1",
"created_at": "2024-01-15",
"document_type": "tutorial"
}
}
```
```json Hybrid theme={null}
{
"id": "document1#chunk1",
"values": [0.0236663818359375, -0.032989501953125, ..., -0.01041412353515625, 0.0086669921875],
"sparse_values": {
"values": [1.7958984, 0.41577148, ..., 4.4414062, 3.3554688],
"indices": [822745112, 1009084850, ..., 3517203014, 3590924191]
},
"metadata": {
"document_id": "document1",
"document_title": "Introduction to Vector Databases",
"chunk_number": 1,
"chunk_text": "First chunk of the document content...",
"document_url": "https://example.com/docs/document1",
"created_at": "2024-01-15",
"document_type": "tutorial"
}
}
```
When you upsert raw text for Pinecone to convert to vectors automatically, each record consists of the following:
* **ID**: A unique string identifier for the record.
* **Text**: The raw text for Pinecone to convert to a dense vector for [semantic search](/guides/search/semantic-search) or a sparse vector for [sparse-vector lexical search](/guides/search/lexical-search), depending on the [embedding model](/guides/index-data/create-an-index#embedding-models) integrated with the index. This field name must match the `embed.field_map` defined in the index.
* **Metadata** (optional): All additional fields are stored as record metadata. You can filter by metadata when searching or deleting records.
Upserting raw text is supported only for [indexes with integrated embedding](/guides/index-data/indexing-overview#vector-embedding).
Example:
```json theme={null}
{
"_id": "document1#chunk1",
"chunk_text": "First chunk of the document content...", // Text to convert to a vector.
"document_id": "document1", // This and subsequent fields stored as metadata.
"document_title": "Introduction to Vector Databases",
"chunk_number": 1,
"document_url": "https://example.com/docs/document1",
"created_at": "2024-01-15",
"document_type": "tutorial"
}
```
## Use structured IDs
Use a structured, human-readable format for record IDs, including ID prefixes that reflect the type of data you're storing, for example:
* **Document chunks**: `document_id#chunk_number`
* **User data**: `user_id#data_type#item_id`
* **Multi-tenant data**: `tenant_id#document_id#chunk_id`
Choose a delimiter for your ID prefixes that won't appear elsewhere in your IDs. Common patterns include:
* `document1#chunk1` - Using hash delimiter
* `document1_chunk1` - Using underscore delimiter
* `document1:chunk1` - Using colon delimiter
Structuring IDs in this way provides several advantages:
* **Efficiency**: Applications can quickly identify which record it should operate on.
* **Clarity**: Developers can easily understand what they're looking at when examining records.
* **Flexibility**: ID prefixes enable list operations for fetching and updating records.
## Include metadata
Include [metadata key-value pairs](/guides/index-data/indexing-overview#metadata) that support your application's key operations, for example:
* **Enable query-time filtering**: Add fields for time ranges, categories, or other criteria for [filtering searches for increased accuracy and relevance](/guides/search/filter-by-metadata).
* **Link related chunks**: Use fields like `document_id` and `chunk_number` to keep track of related records and enable efficient [chunk deletion](#delete-chunks) and [document updates](#update-an-entire-document).
* **Link back to original data**: Include `chunk_text` or `document_url` for traceability and user display.
Metadata keys must be strings, and metadata values must be one of the following data types:
* String
* Number (stored as a 64-bit floating point)
* Boolean (true, false)
* List of strings
Pinecone supports 40 KB of metadata per record.
## Example
This example demonstrates how to manage document chunks in Pinecone using structured IDs and comprehensive metadata. It covers the complete lifecycle of chunked documents: upserting, searching, fetching, updating, and deleting chunks, and updating an entire document.
### Upsert chunks
When [upserting](/guides/index-data/upsert-data) documents that have been split into chunks, combine structured IDs with comprehensive metadata:
Upserting raw text is supported only for [indexes with integrated embedding](/guides/index-data/create-an-index#integrated-embedding).
```python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
index = pc.Index(host="INDEX_HOST")
index.upsert_records(
"example-namespace",
[
{
"_id": "document1#chunk1",
"chunk_text": "First chunk of the document content...",
"document_id": "document1",
"document_title": "Introduction to Vector Databases",
"chunk_number": 1,
"document_url": "https://example.com/docs/document1",
"created_at": "2024-01-15",
"document_type": "tutorial"
},
{
"_id": "document1#chunk2",
"chunk_text": "Second chunk of the document content...",
"document_id": "document1",
"document_title": "Introduction to Vector Databases",
"chunk_number": 2,
"document_url": "https://example.com/docs/document1",
"created_at": "2024-01-15",
"document_type": "tutorial"
},
{
"_id": "document1#chunk3",
"chunk_text": "Third chunk of the document content...",
"document_id": "document1",
"document_title": "Introduction to Vector Databases",
"chunk_number": 3,
"document_url": "https://example.com/docs/document1",
"created_at": "2024-01-15",
"document_type": "tutorial"
},
]
)
```
```python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
index = pc.Index(host="INDEX_HOST")
index.upsert(
namespace="example-namespace",
vectors=[
{
"id": "document1#chunk1",
"values": [0.0236663818359375, -0.032989501953125, ..., -0.01041412353515625, 0.0086669921875],
"metadata": {
"document_id": "document1",
"document_title": "Introduction to Vector Databases",
"chunk_number": 1,
"chunk_text": "First chunk of the document content...",
"document_url": "https://example.com/docs/document1",
"created_at": "2024-01-15",
"document_type": "tutorial"
}
},
{
"id": "document1#chunk2",
"values": [-0.0412445068359375, 0.028839111328125, ..., 0.01953125, -0.0174560546875],
"metadata": {
"document_id": "document1",
"document_title": "Introduction to Vector Databases",
"chunk_number": 2,
"chunk_text": "Second chunk of the document content...",
"document_url": "https://example.com/docs/document1",
"created_at": "2024-01-15",
"document_type": "tutorial"
}
},
{
"id": "document1#chunk3",
"values": [0.0512237548828125, 0.041656494140625, ..., 0.02130126953125, -0.0394287109375],
"metadata": {
"document_id": "document1",
"document_title": "Introduction to Vector Databases",
"chunk_number": 3,
"chunk_text": "Third chunk of the document content...",
"document_url": "https://example.com/docs/document1",
"created_at": "2024-01-15",
"document_type": "tutorial"
}
}
]
)
```
### Search chunks
To search the chunks of a document, use a [metadata filter expression](/guides/search/filter-by-metadata#metadata-filter-expressions) that limits the search appropriately:
Searching with text is supported only for [indexes with integrated embedding](/guides/index-data/create-an-index#integrated-embedding).
```python Python theme={null}
from pinecone import Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
index = pc.Index(host="INDEX_HOST")
filtered_results = index.search(
namespace="example-namespace",
query={
"inputs": {"text": "What is a vector database?"},
"top_k": 3,
"filter": {"document_id": "document1"}
},
fields=["chunk_text"]
)
print(filtered_results)
```
```python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
index = pc.Index(host="INDEX_HOST")
filtered_results = index.query(
namespace="example-namespace",
vector=[0.0236663818359375,-0.032989501953125, ..., -0.01041412353515625,0.0086669921875],
top_k=3,
filter={
"document_id": {"$eq": "document1"}
},
include_metadata=True,
include_values=False
)
print(filtered_results)
```
### Fetch chunks
To retrieve all chunks for a specific document, first [list the record IDs](/guides/manage-data/list-record-ids) using the document prefix, and then [fetch](/guides/manage-data/fetch-data) the complete records:
```python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
index = pc.Index(host="INDEX_HOST")
# List all chunks for document1 using ID prefix
chunk_ids = []
for record_id in index.list(prefix='document1#', namespace='example-namespace'):
chunk_ids.append(record_id)
print(f"Found {len(chunk_ids)} chunks for document1")
# Fetch the complete records by ID
if chunk_ids:
records = index.fetch(ids=chunk_ids, namespace='example-namespace')
for record_id, record_data in records['vectors'].items():
print(f"Chunk ID: {record_id}")
print(f"Chunk text: {record_data['metadata']['chunk_text']}")
# Process the vector values and metadata as needed
```
Pinecone is [eventually consistent](/guides/index-data/check-data-freshness), so it's possible that a write (upsert, update, or delete) followed immediately by a read (query, list, or fetch) may not return the latest version of the data. If your use case requires retrieving data immediately, consider implementing a small delay or [retry logic](/guides/production/error-handling#implement-retry-logic) after writes.
### Update chunks
To [update](/guides/manage-data/update-data) specific chunks within a document, first list the chunk IDs, and then update individual records:
```python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
index = pc.Index(host="INDEX_HOST")
# List all chunks for document1
chunk_ids = []
for record_id in index.list(prefix='document1#', namespace='example-namespace'):
chunk_ids.append(record_id)
# Update specific chunks (e.g., update chunk 2)
if 'document1#chunk2' in chunk_ids:
new_vector = ... # from your embedding model
index.update(
id='document1#chunk2',
values=new_vector,
set_metadata={
"document_id": "document1",
"document_title": "Introduction to Vector Databases - Revised",
"chunk_number": 2,
"chunk_text": "Updated second chunk content...",
"document_url": "https://example.com/docs/document1",
"created_at": "2024-01-15",
"updated_at": "2024-02-15",
"document_type": "tutorial"
},
namespace='example-namespace'
)
print("Updated chunk 2 successfully")
```
### Delete chunks
To [delete](/guides/manage-data/delete-data#delete-records-by-metadata) chunks of a document, use a [metadata filter expression](/guides/search/filter-by-metadata#metadata-filter-expressions) that limits the deletion appropriately:
```python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
index = pc.Index(host="INDEX_HOST")
# Delete chunks 1 and 3
index.delete(
namespace="example-namespace",
filter={
"document_id": {"$eq": "document1"},
"chunk_number": {"$in": [1, 3]}
}
)
# Delete all chunks for a document
index.delete(
namespace="example-namespace",
filter={
"document_id": {"$eq": "document1"}
}
)
```
### Update an entire document
If you need to update most of the records in a large namespace, [contact Support](https://app.pinecone.io/organizations/-/settings/support/ticket) for help creating an export to enable a faster and more cost-effective approach.
When the amount of chunks or ordering of chunks for a document changes, the recommended approach is to first [delete all chunks using a metadata filter](/guides/manage-data/delete-data#delete-records-by-metadata), and then [upsert](/guides/index-data/upsert-data) the new chunks:
```python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
index = pc.Index(host="INDEX_HOST")
# Step 1: Delete all existing chunks for the document
index.delete(
namespace="example-namespace",
filter={
"document_id": {"$eq": "document1"}
}
)
print("Deleted existing chunks for document1")
# Step 2: Upsert the updated document chunks
chunk1_vector = ... # from your embedding model
chunk2_vector = ...
index.upsert(
namespace="example-namespace",
vectors=[
{
"id": "document1#chunk1",
"values": chunk1_vector,
"metadata": {
"document_id": "document1",
"document_title": "Introduction to Vector Databases - Updated Edition",
"chunk_number": 1,
"chunk_text": "Updated first chunk with new content...",
"document_url": "https://example.com/docs/document1",
"created_at": "2024-02-15",
"document_type": "tutorial",
"version": "2.0"
}
},
{
"id": "document1#chunk2",
"values": chunk2_vector,
"metadata": {
"document_id": "document1",
"document_title": "Introduction to Vector Databases - Updated Edition",
"chunk_number": 2,
"chunk_text": "Updated second chunk with new content...",
"document_url": "https://example.com/docs/document1",
"created_at": "2024-02-15",
"document_type": "tutorial",
"version": "2.0"
}
}
# Add more chunks as needed for the updated document
]
)
print("Successfully updated document1 with new chunks")
```
## Data freshness
Pinecone is [eventually consistent](/guides/index-data/check-data-freshness), so it's possible that a write (upsert, update, or delete) followed immediately by a read (query, list, or fetch) may not return the latest version of the data. If your use case requires retrieving data immediately, consider implementing a small delay or [retry logic](/guides/production/error-handling#implement-retry-logic) after writes.
## Design for multi-tenancy
Many applications have a concept of tenants—users, organizations, projects, or other groups that should only access their own data. How you model this access control significantly impacts query performance and cost.
### Use namespaces for tenant isolation
The most efficient way to implement multi-tenancy is to use [namespaces](/guides/index-data/indexing-overview#namespaces) to separate data by tenant. With this approach, each tenant has their own namespace, and queries only scan that tenant's data—resulting in better performance and lower costs.
For a complete implementation guide with examples across all SDKs, see [Implement multitenancy](/guides/index-data/implement-multitenancy).
When you use namespaces for multi-tenancy:
* **Lower query costs and faster performance**: Query cost is based on namespace size. If you have 100 tenants with 1 GB each, querying one tenant's namespace costs 1 RU and scans only 1 GB. With metadata filtering in a single namespace (100 GB total), the same query costs 100 RUs and scans all 100 GB, even though the filter narrows results.
* **Natural isolation**: Reduces the risk of application bugs that could query the wrong tenant's data (for example, by passing an incorrect filter value).
### Avoid filtering by high-cardinality IDs
A common anti-pattern is storing all data in a single namespace and using metadata filters to scope queries to specific users:
```python Python theme={null}
# Anti-pattern: Filtering by many user IDs
query_vector = [0.1, 0.2, 0.3, ...] # Your query vector
results = index.query(
vector=query_vector,
top_k=10,
filter={
"allowed_user_ids": {"$in": ["user_1", "user_2", ..., "user_10000"]}
}
)
```
```javascript JavaScript theme={null}
// Anti-pattern: Filtering by many user IDs
const queryVector = [0.1, 0.2, 0.3, ...]; // Your query vector
const results = await index.query({
vector: queryVector,
topK: 10,
filter: {
allowed_user_ids: { $in: ["user_1", "user_2", ..., "user_10000"] }
}
});
```
```java Java theme={null}
// Anti-pattern: Filtering by many user IDs
import com.google.protobuf.Struct;
import com.google.protobuf.Value;
import io.pinecone.clients.Index;
import io.pinecone.clients.Pinecone;
import io.pinecone.unsigned_indices_model.QueryResponseWithUnsignedIndices;
import java.util.Arrays;
import java.util.List;
Pinecone pinecone = new Pinecone.Builder("YOUR_API_KEY").build();
Index index = pinecone.getIndexConnection("your-index-name");
List queryVector = Arrays.asList(0.1f, 0.2f, 0.3f, ...); // Your query vector
// Build filter with $in operator (up to 10,000 values)
Struct.Builder filterBuilder = Struct.newBuilder();
Value.Builder listValueBuilder = Value.newBuilder();
listValueBuilder.getListValueBuilder()
.addAllValues(Arrays.asList(
Value.newBuilder().setStringValue("user_1").build(),
Value.newBuilder().setStringValue("user_2").build()
// ... up to 10,000 values
));
filterBuilder.putFields("allowed_user_ids",
Value.newBuilder()
.setStructValue(Struct.newBuilder()
.putFields("$in", listValueBuilder.build())
.build())
.build());
Struct filter = filterBuilder.build();
QueryResponseWithUnsignedIndices results = index.queryByVector(
10,
queryVector,
null, // default namespace
filter
);
```
```go Go theme={null}
// Anti-pattern: Filtering by many user IDs
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v5/pinecone"
"google.golang.org/protobuf/types/known/structpb"
)
ctx := context.Background()
clientParams := pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
}
pc, err := pinecone.NewClient(clientParams)
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
idx, err := pc.DescribeIndex(ctx, "your-index-name")
if err != nil {
log.Fatalf("Failed to describe index: %v", err)
}
idxConnection, err := pc.Index(pinecone.NewIndexConnParams{
Host: idx.Host,
})
if err != nil {
log.Fatalf("Failed to create IndexConnection: %v", err)
}
queryVector := []float32{0.1, 0.2, 0.3, ...} // Your query vector
userIds := []interface{}{"user_1", "user_2", /* ... up to 10,000 values */}
metadataMap := map[string]interface{}{
"allowed_user_ids": map[string]interface{}{
"$in": userIds,
},
}
filter, err := structpb.NewStruct(metadataMap)
if err != nil {
log.Fatalf("Failed to create filter: %v", err)
}
queryReq := &pinecone.QueryByVectorValuesRequest{
Vector: queryVector,
TopK: 10,
MetadataFilter: filter,
IncludeMetadata: true,
}
results, err := idxConnection.QueryByVectorValues(ctx, queryReq)
if err != nil {
log.Fatalf("Failed to query: %v", err)
}
fmt.Printf("Found %d matches:\n", len(results.Matches))
for _, match := range results.Matches {
fmt.Printf(" ID: %s, Score: %.4f\n", match.Vector.Id, match.Score)
if match.Vector.Metadata != nil {
fmt.Printf(" Metadata: %v\n", match.Vector.Metadata)
}
}
```
```bash curl theme={null}
# Anti-pattern: Filtering by many user IDs
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
curl -X POST "https://$INDEX_HOST/query" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "Content-Type: application/json" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"vector": [0.1, 0.2, 0.3, ...],
"topK": 10,
"includeMetadata": true,
"filter": {
"allowed_user_ids": {
"$in": ["user_1", "user_2", ..., "user_10000"]
}
}
}'
```
This approach has several drawbacks:
* **Performance degradation**: Large `$in` filters increase network payload size and query latency.
* **Hard limits**: Each `$in` or `$nin` operator is limited to 10,000 values. Exceeding this limit will cause the request to fail. See [Metadata filter limits](/reference/api/database-limits#metadata-filter-limits).
### Use access control groups instead of individual IDs
If data must be shared across many tenants, design your access control using the smallest number of groups that describe a user's access:
```python Python theme={null}
# Better: Filter by organization or role instead of individual users
query_vector = [0.1, 0.2, 0.3, ...] # Your query vector
results = index.query(
vector=query_vector,
top_k=10,
filter={
"$or": [
{"organization_id": {"$eq": "org_A"}},
{"project_id": {"$eq": "project_B"}}
]
}
)
```
```javascript JavaScript theme={null}
// Better: Filter by organization or role instead of individual users
const queryVector = [0.1, 0.2, 0.3, ...]; // Your query vector
const results = await index.query({
vector: queryVector,
topK: 10,
filter: {
$or: [
{ organization_id: { $eq: "org_A" } },
{ project_id: { $eq: "project_B" } }
]
}
});
```
```java Java theme={null}
// Better: Filter by organization or role instead of individual users
import com.google.protobuf.Struct;
import com.google.protobuf.Value;
import io.pinecone.clients.Index;
import io.pinecone.clients.Pinecone;
import io.pinecone.unsigned_indices_model.QueryResponseWithUnsignedIndices;
import java.util.Arrays;
import java.util.List;
Pinecone pinecone = new Pinecone.Builder("YOUR_API_KEY").build();
Index index = pinecone.getIndexConnection("your-index-name");
List queryVector = Arrays.asList(0.1f, 0.2f, 0.3f, ...); // Your query vector
// Build filter with $or operator
Struct.Builder orgFilterBuilder = Struct.newBuilder();
orgFilterBuilder.putFields("organization_id",
Value.newBuilder()
.setStructValue(Struct.newBuilder()
.putFields("$eq", Value.newBuilder()
.setStringValue("org_A")
.build())
.build())
.build());
Struct.Builder projectFilterBuilder = Struct.newBuilder();
projectFilterBuilder.putFields("project_id",
Value.newBuilder()
.setStructValue(Struct.newBuilder()
.putFields("$eq", Value.newBuilder()
.setStringValue("project_B")
.build())
.build())
.build());
Struct.Builder orFilterBuilder = Struct.newBuilder();
orFilterBuilder.putFields("$or",
Value.newBuilder()
.getListValueBuilder()
.addValues(Value.newBuilder().setStructValue(orgFilterBuilder.build()).build())
.addValues(Value.newBuilder().setStructValue(projectFilterBuilder.build()).build())
.build());
QueryResponseWithUnsignedIndices results = index.queryByVector(
10,
queryVector,
null, // default namespace
orFilterBuilder.build(),
false, // includeValues
true // includeMetadata
);
```
```go Go theme={null}
// Better: Filter by organization or role instead of individual users
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v5/pinecone"
"google.golang.org/protobuf/types/known/structpb"
)
ctx := context.Background()
clientParams := pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
}
pc, err := pinecone.NewClient(clientParams)
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
idx, err := pc.DescribeIndex(ctx, "your-index-name")
if err != nil {
log.Fatalf("Failed to describe index: %v", err)
}
idxConnection, err := pc.Index(pinecone.NewIndexConnParams{
Host: idx.Host,
})
if err != nil {
log.Fatalf("Failed to create IndexConnection: %v", err)
}
queryVector := []float32{0.1, 0.2, 0.3, ...} // Your query vector
metadataMap := map[string]interface{}{
"$or": []interface{}{
map[string]interface{}{
"organization_id": map[string]interface{}{
"$eq": "org_A",
},
},
map[string]interface{}{
"project_id": map[string]interface{}{
"$eq": "project_B",
},
},
},
}
filter, err := structpb.NewStruct(metadataMap)
if err != nil {
log.Fatalf("Failed to create filter: %v", err)
}
queryReq := &pinecone.QueryByVectorValuesRequest{
Vector: queryVector,
TopK: 10,
MetadataFilter: filter,
IncludeMetadata: true,
}
results, err := idxConnection.QueryByVectorValues(ctx, queryReq)
if err != nil {
log.Fatalf("Failed to query: %v", err)
}
fmt.Printf("Found %d matches:\n", len(results.Matches))
for _, match := range results.Matches {
fmt.Printf(" ID: %s, Score: %.4f\n", match.Vector.Id, match.Score)
if match.Vector.Metadata != nil {
fmt.Printf(" Metadata: %v\n", match.Vector.Metadata)
}
}
```
```bash curl theme={null}
# Better: Filter by organization or role instead of individual users
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
curl -X POST "https://$INDEX_HOST/query" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "Content-Type: application/json" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"vector": [0.1, 0.2, 0.3, ...],
"topK": 10,
"includeMetadata": true,
"filter": {
"$or": [
{"organization_id": {"$eq": "org_A"}},
{"project_id": {"$eq": "project_B"}}
]
}
}'
```
Instead of passing thousands of user IDs, this filter uses only 2 group identifiers to achieve the same access control.
### Multitenancy patterns
The following table provides general guidelines for choosing a multitenancy approach. Evaluate your specific use case, access patterns, and requirements to determine the best fit for your application.
| Data pattern | Recommended approach | Query cost | Performance |
| :---------------------------------------- | :-------------------------------------------------------------------- | :------------------------------------- | :---------- |
| Each tenant's data is completely separate | One index, one namespace per tenant | Lowest (scans only tenant namespace) | Fastest |
| Large tenants with many sub-groups | One index per large tenant, namespaces for sub-groups | Low (scans only sub-group namespace) | Fast |
| Data shared across tenants | One index, shared namespace, filter by group IDs (org, project, role) | Higher (scans entire shared namespace) | Slower |
Avoid filtering by large lists of individual user IDs (for example, `{"user_id": {"$in": ["user_1", "user_2", ..., "user_10000"]}}`). This approach has the following drawbacks:
* Hard limits: Each `$in` or `$nin` operator is limited to 10,000 values. Exceeding this limit will cause requests to fail.
* Performance: Large filters increase query latency.
* Higher costs: You pay for scanning the entire shared namespace, even though the filter narrows results.
Instead, consider these alternatives:
* Use one namespace per tenant (see row 1 in the table above).
* Filter by broader groups like organization, project, or role rather than individual user IDs (see row 3 in the table above).
* Retrieve a larger top K without filtering (for example, top 1000), then filter the results client-side.
For a complete step-by-step implementation guide, see [Implement multitenancy](/guides/index-data/implement-multitenancy).
# Dedicated Read Nodes
Source: https://docs.pinecone.io/guides/index-data/dedicated-read-nodes
Dedicated read nodes use provisioned hardware for read operations, providing predictable, low-latency performance at high query volumes.
## Overview
Pinecone indexes built on dedicated read nodes use provisioned read hardware to provide predictable, consistent performance at sustained, high query volumes. They're designed for large-scale vector workloads such as semantic search, recommendation engines, and mission-critical services.
Dedicated read nodes differ from on-demand indexes in how they handle read operations. While on-demand indexes use shared, multi-tenant capacity for reads, dedicated read nodes provision exclusive hardware for reads—memory, local SSDs, and compute. Both index types use Pinecone's serverless infrastructure for writes and storage.
When you create a dedicated read nodes index, Pinecone provisions resources based on your choice of [node type](#node-types), number of [shards](#shards), and number of [replicas](#replicas). These resources include local SSDs and memory that cache all your index data, and provide dedicated query executors to handle read operations (query, fetch, list). This architecture eliminates cold starts and ensures consistent low-latency performance, even under heavy load.
Dedicated read nodes support dense, sparse, hybrid, and [full-text search](/guides/search/full-text-search) indexes, giving you flexibility in your search and retrieval strategy. Because storage (shards) and compute (replicas) scale independently, you can optimize for your specific workload characteristics.
## On-demand vs dedicated
On-demand indexes and dedicated read nodes are both built on Pinecone's serverless infrastructure. They use the same write path, storage layer, and data operations API.
However, every dedicated read nodes index has isolated hardware for read operations (query, fetch, list), allowing these operations to run on dedicated query executors. This affects performance, cost, and how you scale:
| Feature | On-demand | Dedicated read nodes |
| :---------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Read infrastructure** | Multi-tenant compute resources shared across customers | Isolated, provisioned query executors dedicated to your index |
| **Read costs** | Pay per [read unit](/guides/manage-cost/understanding-cost#serverless-indexes) (1 RU per 1 GB of namespace size per query, minimum 0.25 RU) | Fixed hourly rate for read capacity based on node type, shards, and replicas |
| **Other costs** | [Storage](/guides/manage-cost/understanding-cost#storage) and [write](/guides/manage-cost/understanding-cost#write-units) costs based on usage | [Storage](/guides/manage-cost/understanding-cost#storage) and [write](/guides/manage-cost/understanding-cost#write-units) costs based on usage (same as on-demand) |
| **Caching** | Best-effort; frequently accessed data is cached, but cold queries fetch from object storage | Guaranteed; all index data always warm in memory and on local SSDs |
| **Read rate limits** | [2,000 RUs/second per index (adjustable)](/reference/api/database-limits#rate-limits) | No read rate limits (only bounded by CPU capacity) |
| **Scaling** | Automatic; Pinecone handles capacity | Manual; add [shards](#shards) for storage, add [replicas](#replicas) for throughput |
| **Query-time tuning** | Parameters accepted but have no effect | Optional [`scan_factor` and `max_candidates`](#query-time-search-parameters) to trade recall for lower latency and higher throughput |
| **Best for** | Variable workloads, multi-tenant applications with many namespaces, low to moderate query rates | Sustained high query rates, large single-namespace workloads, predictable performance and cost |
## When to use dedicated read nodes
Dedicated read nodes are ideal for workloads with millions to billions of records and predictable query rates. They provide performance and cost benefits compared to on-demand for high-throughput workloads, and may be required when your workload exceeds on-demand rate limits.
There's no universal formula for choosing between on-demand and dedicated read nodes—performance and cost vary by workload (vector dimensionality, metadata filtering, and query patterns). Consider the following factors when making your decision:
With dedicated read nodes, you allocate dedicated read hardware for your index, and your data is cached in memory and on local SSDs. This provides:
* Consistent low latency under heavy load.
* No cold starts (fetching data from object storage).
* Performance isolation from other workloads.
* Linear scaling by adding replicas.
* Predictable costs based on fixed hourly rates for provisioned hardware.
If predictable performance and cost are critical for your application, dedicated read nodes may be a better fit than on-demand.
On-demand indexes are subject to [read unit rate limits](/reference/api/database-limits#rate-limits) (default: 2,000 RUs/second per index).
A high query volume on a large index can exceed these limits. For example, a 15 GB namespace at 150 QPS requires approximately 2,250 RUs/second (`15 RUs per query × 150 QPS`), which exceeds the default rate limit.
Dedicated read nodes have no read rate limits and provide dedicated capacity for predictable QPS without throttling (bounded only by CPU capacity), making them better suited for high-throughput workloads.
Recommendation engines for use cases such as e-commerce and media require very high throughput and low latency to maintain positive user experiences. Dedicated read nodes are purpose-built for these use cases, providing:
* Consistent performance for thousands of queries per second
* Low latency for real-time recommendations
* Scalability to billion-vector datasets
* No performance degradation during traffic spikes
Similar requirements apply to other real-time use cases like semantic search at scale, personalization engines, and mission-critical services with strict performance SLOs.
Dedicated read nodes indexes support only a single namespace. If your application requires multiple namespaces, on-demand is a better fit.
Multi-namespace support is coming soon. For early access, [contact us](https://www.pinecone.io/contact/).
On-demand indexes are better suited for workloads with unpredictable or highly variable traffic patterns. For example:
* RAG systems with variable query volumes
* Agentic applications with sporadic usage
* Prototypes and development environments with intermittent activity
* Scheduled jobs with infrequent, batch-style queries
Additionally, on-demand is better for indexes with many namespaces, even if you have high query volumes. Dedicated read nodes currently only support single-namespace indexes, so multi-tenant applications requiring namespace-based isolation should use on-demand until multi-namespace support is available.
For these scenarios, on-demand's elasticity and usage-based pricing provide better cost efficiency than provisioning dedicated capacity.
Dedicated read nodes **can** handle predictable traffic spikes efficiently if you scale replicas proactively via the API. For example, you can provision extra replicas before a scheduled email campaign and scale back down afterward. Auto-scaling will be available in a future release.
On-demand and dedicated read nodes have different cost structures. The key difference is read costs: on-demand uses usage-based pricing, while dedicated read nodes use a fixed hourly rate based on provisioned hardware. Write and storage costs are usage-based for both modes.
Dedicated read nodes become cost-effective when you have predictable, sustained query volumes that make full use of your provisioned capacity. With unpredictable or low query volumes, you pay hourly rates even when your machines sit idle, making on-demand's usage-based pricing more economical.
For detailed cost information, comparison tables, and estimation tools, see the [Cost](#cost) section of this guide.
Performance depends on your specific workload — index size, vector dimensionality, metadata filtering, query patterns, throughput requirements, and latency requirements. Testing is the only way to know for sure whether dedicated read nodes are right for your scenario.
For a step-by-step guide to testing, see [Test your workload](#test-your-workload).
If you need guidance choosing a capacity mode (on-demand or dedicated read nodes) or sizing your index configuration, [contact us](https://www.pinecone.io/contact/).
## Key concepts
Before creating a dedicated read nodes index, understand the configuration options that determine capacity and performance.
### Node types
A node is the basic unit of compute and cache storage capacity for a dedicated read nodes index. Each shard runs on one node, so the node type you choose determines the performance characteristics and cost of your index. The total number of nodes in your index is calculated as `shards × replicas`. For example, an index with two shards and two replicas uses four nodes.
There are two node types: `b1` and `t1`. Both are suitable for large-scale and demanding workloads, but they differ in processing power and memory capacity, and they cache different data.
| | **b1 (Balanced)** | **t1 (Performance)** |
| -------------------- | ------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| **Memory caching** | Vector index stored in memory | Vector index + vector projections cached in memory |
| **Use case** | Predictable performance for sustained query rates with balanced cost efficiency | Highest performance for the most demanding workloads with extreme query volumes and strict latency requirements |
| **Storage** | 250 GB per shard | 250 GB per shard |
| **Compute & memory** | Base-level compute and memory resources | \~4x more compute and memory than `b1` |
| **Cost** | Lower-cost option | \~3x the cost of `b1` |
Consider using `t1` nodes if your performance requirements are not met by `b1` nodes, or if `t1` nodes are more cost-effective than `b1` nodes for your workload.
When choosing a node type, remember that:
* Both types of nodes provide 250 GB of storage per shard. The difference is in compute and memory, which affects query performance.
* Because `t1` nodes cache more data in memory than `b1` nodes, an index may require more shards on `t1` than on `b1` (for the same data).
* You can [change node types](#change-node-types) after creating your index.
### Shards
Shards determine the storage capacity of an index. Each shard provides 250 GB of storage, and data is split across all the shards in an index. To respond to a query, the index gathers data from all shards as needed. To determine how many shards you need, [calculate your index size](#calculate-the-size-of-your-index) and then [calculate the number of shards](#number-of-shards).
It's your responsibility to allocate enough shards to accommodate the size of your index. If your index exceeds the capacity of its shards, write operations (upsert, update, delete) are blocked, but read operations continue to work normally.
### Replicas
Replicas multiply the compute resources and data of an index, allowing for higher query throughput and availability. Each replica is a complete copy of your index data and has its own dedicated compute resources.
* Throughput scales approximately linearly with replicas. For example, if one replica handles 50 QPS at your target latency, two replicas should handle approximately 100 QPS.
* You can scale replicas up or down with no downtime using the API. See [Add or remove replicas](#add-or-remove-replicas).
* Minimum: 0 replicas ([pauses the index](#pause-an-index)).
* For high availability, use at least two replicas. The recommended approach is to allocate `n+1` replicas where `n` is your minimum for throughput. Pinecone distributes replicas across availability zones (up to three per region), so if one zone fails, remaining replicas continue serving queries.
To determine how many replicas you need, [test your workload](#test-your-workload) and then [calculate the number of replicas](#number-of-replicas).
Actual performance varies based on workload characteristics (query complexity, vector dimensions, metadata characteristics), [metadata filter](/guides/search/filter-by-metadata) selectivity, and [node type](#node-types) (`b1` vs `t1`). Always test with your specific workload.
### Index fullness
Index fullness measures how much of your index's allocated capacity is being used. To ensure predictable performance, dedicated read nodes cache your data in memory and on local SSD.
* You can use Pinecone's API to [check index fullness](#monitor-index-fullness). There are three metrics to monitor: `memoryFullness`, `storageFullness`, and `indexFullness`.
`indexFullness` is the maximum of `memoryFullness` and `storageFullness`.
* Usually, storage fills up first. However, memory can be the limiting factor when you have `b1` nodes with many low-dimension vectors, or when you have `t1` nodes with high-dimension vectors and lots of metadata.
* Monitor fullness regularly and [add shards](#add-or-remove-shards) before your index reaches capacity. When `indexFullness` reaches 1.0 (100%), write operations (upsert, update, delete) are blocked, but read operations continue to work normally.
Add shards when [index fullness](#index-fullness) reaches 70-80%, especially if you expect continued growth. Adding shards reduces storage fullness (index data is spread across shards, so each stores less) and memory fullness (with less data per shard, there's less to cache in memory), helping you avoid write failures.
## Query-time search parameters
Dedicated read nodes support two optional query-time parameters — `scan_factor` and `max_candidates` — that let you trade off recall (search quality) for lower latency and higher throughput. By default, queries use internal heuristics that favor recall. If your application is latency-sensitive or needs higher QPS, you can tune these parameters to reduce the work done per query — or increase them for higher recall.
These parameters only take effect on dedicated read nodes indexes with dense vectors. On on-demand indexes, the parameters are accepted but have no effect. On indexes that store only sparse vectors, specifying either parameter returns an error. Using these parameters requires API version `2025-10` or later.
### How scan\_factor and max\_candidates work
Dense vector search on dedicated read nodes uses a two-stage pipeline:
1. **Scanning** — controlled by `scan_factor`. For IVF-based indexes, the system scans a fraction of partitions determined by `scan_factor / sqrt(num_partitions)`. A lower `scan_factor` scans fewer partitions, producing fewer candidates faster. This parameter only affects IVF-based slabs; for other index architectures (e.g., smaller indexes using flat search), `scan_factor` has no effect.
2. **Reranking** — controlled by `max_candidates`. The top candidates from the scanning stage are reranked by computing exact distances. More reranking improves recall but increases latency. This parameter applies to all index architectures.
The two parameters affect different stages and their effects are additive — you can set both to optimize each stage independently.
| Parameter | Type | Range | Default | Description |
| :------------------- | :------ | :----------------------------------- | :-------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------- |
| **`scan_factor`** | Float | 0.5–4.0 | 4.0 | Controls how much of the IVF index is scanned to find vector candidates. Lower values scan fewer partitions and return results faster. |
| **`max_candidates`** | Integer | Your query's `top_k` value – 100,000 | 2500 (see [default behavior](#default-max_candidates-behavior)) | Maximum number of candidate vectors to rerank with exact distance computation. Higher values improve recall; lower values improve latency. |
You can set one or both per query. Omitting both preserves the current default behavior, so existing applications are unaffected.
#### Default `max_candidates` behavior
When `max_candidates` is not set, the system calculates an effective value using the following formula:
* If `top_k` \<= 1000: `min(top_k * 10, 1000)`
* If `top_k` > 1000: `top_k`
* Then, a floor of 2500 is applied (the effective value is at least 2500)
For most queries (where `top_k` \<= 2500), the effective default is **2500**. This is not the maximum possible value — you can raise `max_candidates` (up to 100,000) to increase recall, or lower it (down to your query's `top_k`) to reduce latency.
When you explicitly set `max_candidates`, the value you provide is used directly, bypassing the formula and the floor.
### Impact on recall and performance
Lower `scan_factor` or `max_candidates` values reduce the work done per query, which improves latency and throughput but may reduce recall. The tables below summarize benchmarked behavior on a 2.68M-vector index (1536 dimensions, cosine similarity). Actual results are dataset-dependent.
#### `scan_factor` benchmarks
Starting from the default (4.0), lowering `scan_factor` reduces the fraction of IVF partitions scanned:
| scan\_factor | Approximate recall (p50) | Relative throughput |
| :------------ | :----------------------- | :------------------ |
| 4.0 (default) | \~96% | 1x (baseline) |
| 2.0 | \~94% | \~1.5x |
| 1.0 | \~91% | \~2x |
| 0.5 | \~84% | \~4x |
Testing shows that lower `scan_factor` values can reduce p50 and p99 latency by 30–50% or more.
#### Tuning `max_candidates`
Higher `max_candidates` improves recall by reranking more candidates but increases latency and reduces throughput; lower values favor speed. For guidance on choosing values, see [Tuning guidance](#tuning-guidance). We recommend benchmarking on your own dataset and workload to find the right balance—use the [Test your workload](#test-your-workload) process to validate latency and recall.
### Tuning guidance
Start with the defaults and adjust based on your workload requirements:
* **To optimize for throughput/latency:** Lower `scan_factor` first (from the default of 4.0). This has the most impact on IVF-based indexes. If you need further improvement, lower `max_candidates` below the default of 2500 (down to your query's `top_k` value).
* **To optimize for recall:** Raise `max_candidates` above the default of 2500 (up to 100,000). This reranks more candidate vectors at the cost of higher latency.
**Trade-offs to consider:**
* **Adjust one parameter at a time.** `scan_factor` controls the scanning stage (IVF only) and `max_candidates` controls the reranking stage (all index types). Tuning them independently makes it easier to isolate the effect.
* **Safe defaults:** Omitting both parameters preserves existing behavior. There is no risk to existing queries.
* **Cost reduction:** By achieving higher throughput per node, you may be able to serve the same query rate with fewer replicas.
### Behavior by vector type
| Index / query type | Behavior |
| :----------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Dense vectors, dense query** | `scan_factor` and `max_candidates` apply normally. |
| **Dense vectors, hybrid query (dense + sparse)** | Both parameters apply to the dense component only; the sparse component is unaffected. |
| **Sparse vectors only** | Specifying `scan_factor` or `max_candidates` returns an error. |
| **On-demand index** | Both parameters are accepted but have no effect on search behavior. You can use the same query code against on-demand (e.g., for development) and dedicated read nodes (for production) without modification. |
### API and SDK examples
Both parameters are optional fields on the `POST /query` request.
```bash curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="YOUR_INDEX_HOST"
curl -X POST "https://$INDEX_HOST/query" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "Content-Type: application/json" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"namespace": "example-namespace",
"topK": 10,
"vector": [0.1, 0.2, 0.3],
"scanFactor": 1.0,
"maxCandidates": 1000
}'
```
```python Python theme={null}
# Both parameters — balanced recall and latency
index.query(
namespace="example-namespace",
vector=[0.1, 0.2, 0.3],
top_k=10,
scan_factor=1.0,
max_candidates=1000
)
# scan_factor only — faster queries, lower recall
index.query(
namespace="example-namespace",
vector=[0.1, 0.2, 0.3],
top_k=10,
scan_factor=0.5
)
# Omit both for maximum recall (default behavior)
index.query(
namespace="example-namespace",
vector=[0.1, 0.2, 0.3],
top_k=10
)
```
```typescript TypeScript theme={null}
// Both parameters — balanced recall and latency
await index.query({
namespace: "example-namespace",
vector: [0.1, 0.2, 0.3],
topK: 10,
scanFactor: 1.0,
maxCandidates: 1000
});
// scan_factor only — faster queries, lower recall
await index.query({
namespace: "example-namespace",
vector: [0.1, 0.2, 0.3],
topK: 10,
scanFactor: 0.5
});
```
**Validation errors:**
| Condition | Error message |
| :-------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------- |
| API version earlier than `2025-10` | `scan_factor and max_candidates parameters require API version 2025-10 or later` |
| `scan_factor` outside 0.5–4.0 | `scan_factor must be between 0.5 and 4.0, got {value}` |
| `max_candidates` below your query's `top_k` or above 100,000 | `max_candidates must be between {top_k} (top_k) and {max}, got {value}` |
| Used on an index that stores only sparse vectors (API error text says "sparse indexes") | `scan_factor and max_candidates parameters are not supported for sparse indexes` |
`scan_factor` and `max_candidates` do not affect billing. Read costs for dedicated read nodes are based on provisioned capacity (node type, shards, and replicas), not per-query effort. By tuning these parameters to achieve higher throughput, you may be able to serve the same query rate with fewer provisioned replicas, reducing your overall cost.
## Test your workload
To choose between on-demand and dedicated read nodes, or to optimize your dedicated read nodes configuration, test with your actual workload. Performance varies based on factors such as the size of your index,vector dimensionality, metadata characteristics, and query patterns.
[Calculate the size of your index](#calculate-the-size-of-your-index) to determine how many shards it requires.
[Create a dedicated read nodes index](#create-a-dedicated-read-nodes-index) with representative data for your workload. You'll use this index for testing.
If you don't restore your test index from a backup, you can [upsert](/guides/index-data/upsert-data) or [import](/guides/index-data/import-data) your data.
If your test index is on-demand, [migrate it to dedicated read nodes](#migrate-to-dedicated-read-nodes). To start, use a single `b1` replica.
Don't migrate your production index yet. At this point, you're just testing your workload.
Run realistic query patterns against your test index, gradually increasing QPS. For example, start at 10 QPS for about 30 minutes, then increase by 10 QPS increments while monitoring latency. Identify the QPS where latency exceeds your target threshold.
Throughput scales approximately linearly with replicas. For example, if one replica handles 50 QPS at your target latency, two replicas should handle approximately 100 QPS. However, performance can vary based on metadata filter selectivity.
To calculate the number of replicas required for your target QPS, use this formula, rounding up:
```
Minimum replicas = (Required QPS) / (QPS per replica)
```
For more information, see [Number of replicas](#number-of-replicas).
To meet your performance and cost goals, adjust your configuration as needed and re-test:
* [Add or remove shards](#add-or-remove-shards) for storage capacity
* [Add or remove replicas](#add-or-remove-replicas) for throughput
* [Change node types](#change-node-types) for different performance characteristics
Continue iterating until you meet your requirements with room for growth.
## Calculate the size of your index
To determine how many [shards](#shards) your index requires, calculate your index size and then use the formula in the [section](#number-of-shards) below.
### Index size
A record can include a dense vector, a sparse vector, or both. Use the formula that matches your data to calculate total size:
An [index of dense vectors](/guides/index-data/indexing-overview#indexes-with-dense-vectors) contains records with one dense vector each.
Records can also contain sparse vectors (when the index metric is set to `dotproduct`), which can be useful for [hybrid search](/guides/search/hybrid-search#use-a-single-index-for-dense-and-sparse-vectors). To learn how to calculate size in that case, see [Index with both dense and sparse vectors](#index-with-both-dense-and-sparse-vectors).
**Calculate size (assuming no sparse vectors)**
```
Index size = Number of records × (
ID size +
Metadata size +
Dense vector dimensions × 4 bytes
)
```
Where:
* `ID size` and `Metadata size` are measured in bytes, averaged across all records.
* Each `Dense vector dimension` uses 4 bytes.
**Example calculations**
These examples assume 8-byte IDs:
| Records | Dense vector dimensions | Avg metadata size | Index size |
| :--------- | :---------------------- | :---------------- | :--------- |
| 500,000 | 768 | 500 bytes | 1.79 GB |
| 1,000,000 | 1536 | 1,000 bytes | 7.15 GB |
| 5,000,000 | 1024 | 15,000 bytes | 95.5 GB |
| 10,000,000 | 1536 | 1,000 bytes | 71.5 GB |
Example: 500,000 records × (8-byte ID + (768 dense vector dimensions × 4 bytes) + 500 bytes of metadata) = 1.79 GB
An [index of sparse vectors](/guides/index-data/indexing-overview#indexes-with-sparse-vectors) contains records with one sparse vector each.
**Calculate size**
```
Index size = Number of records × (
ID size +
Metadata size +
Number of non-zero sparse values × 8 bytes
)
```
Where:
* `ID size` and `Metadata size` are measured in bytes, averaged across all records.
* `Number of non-zero sparse values`: Average number across all records. To find the count for a single record, check the length of the sparse vector's `indices` or `values` array. Each non-zero value uses 8 bytes.
**Example calculations**
These examples assume 8-byte IDs:
| Records | Avg number of non-zero sparse values | Avg metadata size | Index size |
| :--------- | :----------------------------------- | :---------------- | :--------- |
| 500,000 | 10 | 500 bytes | 0.29 GB |
| 1,000,000 | 50 | 1,000 bytes | 1.41 GB |
| 5,000,000 | 100 | 15,000 bytes | 79.0 GB |
| 10,000,000 | 50 | 1,000 bytes | 14.1 GB |
Example: 500,000 records × (8-byte ID + (10 non-zero sparse values × 8 bytes) + 500 bytes of metadata) = 0.29 GB
An [index with both dense and sparse vectors](/guides/search/hybrid-search#use-a-single-index-for-dense-and-sparse-vectors) contains records that each have one dense vector and an optional sparse vector.
**Calculate size**
```
Index size = Number of records × (
ID size +
Metadata size +
Dense vector dimensions × 4 bytes +
Number of non-zero sparse values × 8 bytes
)
```
Where:
* `ID size` and `Metadata size` are measured in bytes, averaged across all records.
* Each `Dense vector dimension` uses 4 bytes.
* `Number of non-zero sparse values`: Average number across all records, including those without sparse vectors. To find the count for a single record, check the length of the sparse vector's `indices` or `values` array. Each non-zero value uses 8 bytes.
**Example calculations**
These examples assume 8-byte IDs:
| Records | Dense vector dimensions | Avg number of non-zero sparse values | Avg metadata size | Index size |
| :--------- | :---------------------- | :----------------------------------- | :---------------- | :--------- |
| 500,000 | 768 | 10 | 500 bytes | 1.83 GB |
| 1,000,000 | 1536 | 50 | 1,000 bytes | 7.54 GB |
| 5,000,000 | 1024 | 100 | 15,000 bytes | 99.5 GB |
| 10,000,000 | 1536 | 50 | 1,000 bytes | 75.4 GB |
Example: 500,000 records × (8-byte ID + (768 dense vector dimensions × 4 bytes) + (10 non-zero sparse values × 8 bytes) + 500 bytes of metadata) = 1.83 GB
### Number of shards
To calculate the number of shards your index requires, divide the size of your index by 250 GB and round up:
```
Minimum shards = (Index size) / (250 GB per shard)
```
To maintain optimal performance, provision additional shards to keep your index at 70-80% capacity. For example, a 500 GB index should have three shards (750 GB capacity = 67% full), not two shards (500 GB capacity = 100% full).
**Example shard calculations**
| Index size | Minimum shards | Recommended shards |
| :----------- | :------------------- | :------------------- |
| **\~71 GB** | 1 (250 GB; 28% full) | 1 (250 GB; 28% full) |
| **\~300 GB** | 2 (500 GB; 60% full) | 2 (500 GB; 60% full) |
| **\~400 GB** | 2 (500 GB; 80% full) | 3 (750 GB; 53% full) |
**Other considerations**
* Every index must have at least one shard. However, you can [pause an index](#pause-an-index) by reducing its replicas to 0.
* After you've created your index, [monitor its fullness](#monitor-index-fullness). When your index approaches capacity, you can [add shards](#add-or-remove-shards).
Add shards when [index fullness](#index-fullness) reaches 70-80%, especially if you expect continued growth. Adding shards reduces storage fullness (index data is spread across shards, so each stores less) and memory fullness (with less data per shard, there's less to cache in memory), helping you avoid write failures.
### Number of replicas
To calculate the number of replicas your index requires, first [test your workload](#test-your-workload) to find the QPS a single replica can handle at your target latency. Then, use this formula, and round up:
```
Minimum replicas = (Required QPS) / (QPS per replica)
```
For example, if one replica handles 50 QPS at your target latency and you need 150 QPS, you need three replicas.
**Other considerations**
* Throughput scales approximately linearly with replicas, but performance can vary based on metadata filter selectivity.
* For high availability, allocate `n+1` replicas where `n` is your minimum for throughput. Pinecone distributes replicas across availability zones.
## Create a dedicated read nodes index
You can create a dedicated read nodes index from scratch or from a backup of an existing index.
### From scratch
To create a new dedicated read nodes index from scratch, call [Create an index](/reference/api/2025-10/control-plane/create_index). In the request body, in the `spec.serverless.read_capacity` object, set the following fields:
| Field | Value | Notes |
| :------------------------------ | :----------------------------------------------- | :----------------------------------------------------- |
| **`mode`** | `Dedicated` | |
| **`dedicated.node_type`** | `b1` or `t1` | See [node types](#node-types) |
| **`dedicated.scaling`** | `Manual` | Currently the only option |
| **`dedicated.manual.shards`** | Number of [shards](#number-of-shards) needed | Minimum 1 shard; each shard provides 250 GB of storage |
| **`dedicated.manual.replicas`** | Number of [replicas](#number-of-replicas) needed | Minimum 0 (this [pauses](#pause-an-index) the index) |
To learn how to determine the number of shards and replicas your index requires, see [Calculate the size of your index](#calculate-the-size-of-your-index).
**Example**
```bash curl expandable theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -X POST "https://api.pinecone.io/indexes" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"name": "example-dedicated-index",
"dimension": 1024,
"metric": "cosine",
"deletion_protection": "enabled",
"tags": {
"environment": "production"
},
"vector_type": "dense",
"spec": {
"serverless": {
"cloud": "aws",
"region": "us-east-1",
"read_capacity": {
"mode": "Dedicated",
"dedicated": {
"node_type": "b1",
"scaling": "Manual",
"manual": {
"shards": 2,
"replicas": 1
}
}
}
}
}
}'
```
Example response:
```jsonc curl expandable theme={null}
{
"name": "example-dedicated-index",
"vector_type": "dense",
"metric": "cosine",
"dimension": 1024,
"status": {
"ready": false,
"state": "Initializing"
},
"host": "example-dedicated-index-1c6ab6aa.svc.aped-4627-b74a.pinecone.io",
"spec": {
"serverless": {
"region": "us-east-1",
"cloud": "aws",
"read_capacity": {
"mode": "Dedicated",
"dedicated": {
"node_type": "b1",
"scaling": "Manual",
"manual": {
"shards": 2, // <---- desired state
"replicas": 1
}
},
"status": {
"state": "Migrating",
"current_shards": null, // <---- current state
"current_replicas": null
}
}
}
},
"deletion_protection": "enabled",
"tags": {
"environment": "production"
}
}
```
The response includes two status fields:
| Field | Description |
| :----------------------------------------------- | :------------------------------------------------------------------------- |
| **`status.state`** | Overall index status (for example, `Initializing`, `Ready`, `Terminating`) |
| **`spec.serverless.read_capacity.status.state`** | Read capacity status (`Migrating`, `Scaling`, `Ready`, `Error`) |
When creating a dedicated read nodes index, `status.state` transitions to `Ready` as soon as the index is ready for reads and writes.
However, `spec.serverless.read_capacity.status.state` remains `Migrating` until the index scales to its full read capacity, at which point it transitions to `Ready`.
After creating the index, [upsert](/guides/index-data/upsert-data) or [import](/guides/index-data/import-data) your data.
To upsert and search with text instead of vectors, you can configure your index to use a [hosted embedding model](/guides/index-data/create-an-index#embedding-models). Call [Configure an index](/reference/api/2025-10/control-plane/configure_index) and specify the `embed` object in the request body.
### From a backup
To create a dedicated read nodes index from a backup:
1. [Restore the backup](/guides/manage-data/restore-an-index). This creates a new on-demand index with the same data as the original.
2. If the restored index has multiple namespaces, [delete](/reference/api/latest/data-plane/deletenamespace) all of them except the one you want to keep. Dedicated read nodes currently only support [one namespace](#namespace-limits).
3. [Migrate the index to dedicated read nodes](#migrate-to-dedicated-read-nodes).
## Migrate to dedicated read nodes
### From a pod-based index
You cannot migrate a pod-based index directly to dedicated read nodes. First complete [Migrate a pod-based index to serverless](/guides/indexes/pods/migrate-a-pod-based-index-to-serverless), which creates a new on-demand index with your data.
If that index has multiple namespaces, consolidate to one namespace, or plan a different architecture. Dedicated read nodes currently support only a [single namespace](#namespace-limits).
### From an on-demand (serverless) index
To migrate an existing on-demand index to dedicated read nodes—including one you created by [migrating from pods](#from-a-pod-based-index)—follow these steps:
[Create a backup](/guides/manage-data/back-up-an-index) of your index. If you later find that on-demand is preferable, you can restore the backup to a new on-demand index or [contact support](https://app.pinecone.io/organizations/-/settings/support/ticket) to migrate back.
If your index has multiple namespaces, [delete](/reference/api/latest/data-plane/deletenamespace) all of them except the one you want to keep. Dedicated read nodes currently only support a [single namespace](#namespace-limits).
If this is a production index, be sure to make a [backup](/guides/manage-data/back-up-an-index) before deleting namespaces. Or, if you need multiple namespaces, [contact support](https://app.pinecone.io/organizations/-/settings/support/ticket) to discuss early access to multi-namespace support for dedicated read nodes.
[Calculate your index size](#index-size) to determine how many [shards](#number-of-shards) you need.
To migrate the index, call [Configure an index](/reference/api/2025-10/control-plane/configure_index). In the request body, in the `spec.serverless.read_capacity` object, set the following fields:
| Field | Value | Notes |
| :------------------------------ | :----------------------------------------------- | :----------------------------------------------------- |
| **`mode`** | `Dedicated` | |
| **`dedicated.node_type`** | `b1` or `t1` | See [node types](#node-types) |
| **`dedicated.scaling`** | `Manual` | Currently the only option |
| **`dedicated.manual.shards`** | Number of [shards](#number-of-shards) needed | Minimum 1 shard; each shard provides 250 GB of storage |
| **`dedicated.manual.replicas`** | Number of [replicas](#number-of-replicas) needed | Minimum 0 (this [pauses](#pause-an-index) the index) |
**Example**
This example migrates an index to dedicated read nodes using `b1` nodes, one shard, and one replica:
```bash curl expandable theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_NAME="YOUR_INDEX_NAME"
curl -X PATCH "https://api.pinecone.io/indexes/$INDEX_NAME" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"spec": {
"serverless": {
"read_capacity": {
"mode": "Dedicated",
"dedicated": {
"node_type": "b1",
"scaling": "Manual",
"manual": {
"shards": 1,
"replicas": 1
}
}
}
}
}
}'
```
Example response:
```jsonc curl expandable theme={null}
{
"name": "example-index-to-migrate",
"vector_type": "dense",
"metric": "cosine",
"dimension": 1024,
"status": {
"ready": true,
"state": "Ready"
},
"host": "example-index-to-migrate-1c6ab6aa.svc.aped-4627-b74a.pinecone.io",
"spec": {
"serverless": {
"region": "us-east-1",
"cloud": "aws",
"read_capacity": {
"mode": "Dedicated",
"dedicated": {
"node_type": "b1",
"scaling": "Manual",
"manual": {
"shards": 1, // <---- desired state
"replicas": 1
}
},
"status": {
"state": "Migrating",
"current_shards": null, //<---- current state
"current_replicas": null
}
}
}
},
"deletion_protection": "disabled",
"tags": null,
"embed": {
"model": "llama-text-embed-v2",
"field_map": {
"text": "text"
},
"dimension": 1024,
"metric": "cosine",
"write_parameters": {
"dimension": 1024,
"input_type": "passage",
"truncate": "END"
},
"read_parameters": {
"dimension": 1024,
"input_type": "query",
"truncate": "END"
},
"vector_type": "dense"
}
}
```
The response includes two status fields:
| Field | Description |
| :----------------------------------------------- | :------------------------------------------------------------------------- |
| **`status.state`** | Overall index status (for example, `Initializing`, `Ready`, `Terminating`) |
| **`spec.serverless.read_capacity.status.state`** | Read capacity status (`Migrating`, `Scaling`, `Ready`, `Error`) |
If `status.state` is set to `Error`, the allocated number of shards was insufficient for the size of the index. Try again, adding more shards as needed.
[Monitor](#check-the-status-of-a-change) the status of the migration. When the migration is complete, `spec.serverless.read_capacity.status.state` is `Ready`.
After migrating, monitor your index performance to verify that it meets expectations.
## Manage your index
The following sections describe how to manage a dedicated read nodes index using version `2025-10` of the Pinecone API.
To upsert and search with text instead of vectors, you can configure your index to use a [hosted embedding model](/guides/index-data/create-an-index#embedding-models). To do this, call [Configure an index](/reference/api/2025-10/control-plane/configure_index) and provide an `embed` object in the request body. In this object:
* For the `text` field, specify the name of the field in your data that contains the text to be embedded.
* Specify a model whose dimension requirements match the dimensions of your index.
**Example**
Example request:
```bash curl expandable theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_NAME="YOUR_INDEX_NAME"
curl -X PATCH "https://api.pinecone.io/indexes/$INDEX_NAME" \
-H "Content-Type: application/json" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"embed": {
"field_map": {
"text": "chunk_text"
},
"model": "llama-text-embed-v2",
"read_parameters": {
"input_type": "query",
"truncate": "NONE"
},
"write_parameters": {
"input_type": "passage"
}
}
}'
```
Example response:
```json curl expandable theme={null}
{
"name": "example-dedicated-index",
"vector_type": "dense",
"metric": "cosine",
"dimension": 1024,
"status": {
"ready": true,
"state": "Ready"
},
"host": "example-dedicated-index-1c6ab6aa.svc.aped-4627-b74a.pinecone.io",
"spec": {
"serverless": {
"region": "us-east-1",
"cloud": "aws",
"read_capacity": {
"mode": "Dedicated",
"dedicated": {
"node_type": "b1",
"scaling": "Manual",
"manual": {
"shards": 2,
"replicas": 1
}
},
"status": {
"state": "Ready",
"current_shards": 2,
"current_replicas": 1
}
}
}
},
"deletion_protection": "enabled",
"tags": {
"environment": "testing"
},
"embed": {
"model": "llama-text-embed-v2",
"field_map": {
"text": "chunk_text"
},
"dimension": 1024,
"metric": "cosine",
"write_parameters": {
"dimension": 1024,
"input_type": "passage",
"truncate": "END"
},
"read_parameters": {
"dimension": 1024,
"input_type": "query",
"truncate": "NONE"
},
"vector_type": "dense"
}
}
```
You can also create a dedicated read nodes index when calling [Create an index with integrated embedding](/reference/api/2025-10/control-plane/create_for_model). In the request body, use the `read_capacity` object to configure node type, shards, and replicas for dedicated read nodes.
To check [index fullness](#index-fullness), call [Get index stats](/reference/api/2025-10/data-plane/describeindexstats).
**Example**
Example request:
```bash curl theme={null}
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="YOUR_INDEX_HOST"
curl -X GET "https://$INDEX_HOST/describe_index_stats" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10"
```
Example response:
```json curl expandable theme={null}
{
"namespaces": {
"__default__": {
"vectorCount": 705000
}
},
"indexFullness": 0.01,
"totalVectorCount": 705000,
"dimension": 1536,
"metric": "cosine",
"vectorType": "dense",
"memoryFullness": 0.01,
"storageFullness": 0.01
}
```
In the response, `indexFullness` describes how full the index is, on a scale of 0 to 1. It's set to the greater of `memoryFullness` and `storageFullness`.
To add or remove [shards](#shards), call [Configure an index](/reference/api/2025-10/control-plane/configure_index). This operation does not require downtime, but can take up to 30 minutes to complete. In the request body, set the following fields:
| Field | Value | Notes |
| :---------------------------------------------------------- | :---------------------------------- | :------------------------------------ |
| **`spec.serverless.read_capacity.mode`** | `Dedicated` | |
| **`spec.serverless.read_capacity.dedicated.scaling`** | `Manual` | |
| **`spec.serverless.read_capacity.dedicated.manual.shards`** | Desired number of [shards](#shards) | Each shard provides 250 GB of storage |
**Example**
Example request:
```bash curl expandable theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_NAME="YOUR_INDEX_NAME"
curl -X PATCH "https://api.pinecone.io/indexes/$INDEX_NAME" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"spec": {
"serverless": {
"read_capacity": {
"mode": "Dedicated",
"dedicated": {
"scaling": "Manual",
"manual": {
"shards": 3
}
}
}
}
}
}'
```
Example response:
```jsonc curl expandable theme={null}
{
"name": "example-dedicated-index",
"vector_type": "dense",
"metric": "cosine",
"dimension": 1024,
"status": {
"ready": true,
"state": "Ready"
},
"host": "example-dedicated-index-1c6ab6aa.svc.aped-4627-b74a.pinecone.io",
"spec": {
"serverless": {
"region": "us-east-1",
"cloud": "aws",
"read_capacity": {
"mode": "Dedicated",
"dedicated": {
"node_type": "b1",
"scaling": "Manual",
"manual": {
"shards": 3, // <---- desired state
"replicas": 1
}
},
"status": {
"state": "Scaling",
"current_shards": 2, // <---- current state
"current_replicas": 1
}
}
}
},
"deletion_protection": "disabled",
"tags": null,
"embed": {
"model": "llama-text-embed-v2",
"field_map": {
"text": "text"
},
"dimension": 1024,
"metric": "cosine",
"write_parameters": {
"dimension": 1024,
"input_type": "passage",
"truncate": "END"
},
"read_parameters": {
"dimension": 1024,
"input_type": "query",
"truncate": "END"
},
"vector_type": "dense"
}
}
```
Configuration change limits:
* You can make one configuration change every ten minutes, but you can batch multiple changes (node type, shards, and replicas) in a single request.
* A new configuration change can only be initiated after the previous configuration change has completed.
* Each configuration change can take up to 30 minutes to complete.
* Read and write operations continue normally during configuration changes.
To add or remove [replicas](#replicas), call [Configure an index](/reference/api/2025-10/control-plane/configure_index). This operation does not require downtime, but can take up to 30 minutes to complete. In the request body, set the following fields:
| Field | Value | Notes |
| :------------------------------------------------------------ | :-------------------------------------- | :---------------------------------------- |
| **`spec.serverless.read_capacity.mode`** | `Dedicated` | |
| **`spec.serverless.read_capacity.dedicated.scaling`** | `Manual` | |
| **`spec.serverless.read_capacity.dedicated.manual.replicas`** | Desired number of [replicas](#replicas) | Add replicas to increase query throughput |
**Example**
Example request:
```bash curl expandable theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_NAME="YOUR_INDEX_NAME"
curl -X PATCH "https://api.pinecone.io/indexes/$INDEX_NAME" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"spec": {
"serverless": {
"read_capacity": {
"mode": "Dedicated",
"dedicated": {
"scaling": "Manual",
"manual": {
"replicas": 2
}
}
}
}
}
}'
```
Example response:
```jsonc curl expandable theme={null}
{
"name": "example-dedicated-index",
"vector_type": "dense",
"metric": "cosine",
"dimension": 1024,
"status": {
"ready": true,
"state": "Ready"
},
"host": "example-dedicated-index-1c6ab6aa.svc.aped-4627-b74a.pinecone.io",
"spec": {
"serverless": {
"region": "us-east-1",
"cloud": "aws",
"read_capacity": {
"mode": "Dedicated",
"dedicated": {
"node_type": "b1",
"scaling": "Manual",
"manual": {
"shards": 1,
"replicas": 2 // <---- desired state
}
},
"status": {
"state": "Scaling",
"current_shards": 1,
"current_replicas": 1 // <---- current state
}
}
}
},
"deletion_protection": "disabled",
"tags": null,
"embed": {
"model": "llama-text-embed-v2",
"field_map": {
"text": "text"
},
"dimension": 1024,
"metric": "cosine",
"write_parameters": {
"dimension": 1024,
"input_type": "passage",
"truncate": "END"
},
"read_parameters": {
"dimension": 1024,
"input_type": "query",
"truncate": "END"
},
"vector_type": "dense"
}
}
```
Configuration change limits:
* You can make one configuration change every ten minutes, but you can batch multiple changes (node type, shards, and replicas) in a single request.
* A new configuration change can only be initiated after the previous configuration change has completed.
* Each configuration change can take up to 30 minutes to complete.
* Read and write operations continue normally during configuration changes.
You can change node types in either direction (`b1` → `t1` or `t1` → `b1`). This operation does not require downtime, but can take up to 30 minutes to complete.
The most predictable way to increase throughput is by increasing [replicas](#replicas).
`t1` nodes [cache more data in memory](#node-types) than `b1` nodes. Because of this, switching from `b1` to `t1` may require more shards.
If your new configuration doesn't have enough shards, the configuration change will fail with an error telling you how many shards are required. Update the request and retry.
In the meantime, your index will continue to function normally in its original configuration.
To change node types, call [Configure an index](/reference/api/2025-10/control-plane/configure_index). In the request body, set the following fields:
| Field | Value | Notes |
| :------------------------------------------------------ | :----------- | :---------------------------- |
| **`spec.serverless.read_capacity.mode`** | `Dedicated` | |
| **`spec.serverless.read_capacity.dedicated.node_type`** | `b1` or `t1` | See [node types](#node-types) |
**Example**
Example request to change from `b1` to `t1`:
```bash curl expandable theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_NAME="YOUR_INDEX_NAME"
curl -X PATCH "https://api.pinecone.io/indexes/$INDEX_NAME" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"spec": {
"serverless": {
"read_capacity": {
"mode": "Dedicated",
"dedicated": {
"node_type": "t1"
}
}
}
}
}'
```
Example response:
```json curl expandable theme={null}
{
"name": "example-dedicated-index",
"vector_type": "dense",
"metric": "cosine",
"dimension": 1024,
"status": {
"ready": true,
"state": "Ready"
},
"host": "example-dedicated-index-1c6ab6aa.svc.aped-4627-b74a.pinecone.io",
"spec": {
"serverless": {
"region": "us-east-1",
"cloud": "aws",
"read_capacity": {
"mode": "Dedicated",
"dedicated": {
"node_type": "t1",
"scaling": "Manual",
"manual": {
"shards": 1,
"replicas": 1
}
},
"status": {
"state": "Scaling",
"current_shards": 1,
"current_replicas": 1
}
}
}
},
"deletion_protection": "disabled",
"tags": null,
"embed": {
"model": "llama-text-embed-v2",
"field_map": {
"text": "text"
},
"dimension": 1024,
"metric": "cosine",
"write_parameters": {
"dimension": 1024,
"input_type": "passage",
"truncate": "END"
},
"read_parameters": {
"dimension": 1024,
"input_type": "query",
"truncate": "END"
},
"vector_type": "dense"
}
}
```
Configuration change limits:
* You can make one configuration change every ten minutes, but you can batch multiple changes (node type, shards, and replicas) in a single request.
* A new configuration change can only be initiated after the previous configuration change has completed.
* Each configuration change can take up to 30 minutes to complete.
* Read and write operations continue normally during configuration changes.
To pause an index, [set the number of replicas](#add-or-remove-replicas) to 0. This operation can take up to 30 minutes to complete.
While an index is paused, you cannot write to it or read from it. For a paused index, you're billed for storage, but not for node costs, reads, or writes.
After making a configuration change to a dedicated read nodes index (changing shards, replicas, or node type), check the status of the change by calling [Describe an index](/reference/api/2025-10/control-plane/describe_index).
**Example**
Example request:
```bash curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_NAME="YOUR_INDEX_NAME"
curl -X GET "https://api.pinecone.io/indexes/$INDEX_NAME" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10"
```
Example response (index scaling from one to two replicas):
```jsonc curl expandable theme={null}
{
"name": "example-dedicated-index",
"vector_type": "dense",
"metric": "cosine",
"dimension": 1536,
"status": {
"ready": true,
"state": "Ready"
},
"host": "example-dedicated-index-1c6ab6aa.svc.aped-4627-b74a.pinecone.io",
"spec": {
"serverless": {
"region": "us-east-1",
"cloud": "aws",
"read_capacity": {
"mode": "Dedicated",
"dedicated": {
"node_type": "b1",
"scaling": "Manual",
"manual": {
"shards": 1,
"replicas": 2 // <---- desired state
}
},
"status": {
"state": "Scaling",
"current_shards": 1,
"current_replicas": 1 // <---- current state
}
}
}
},
"deletion_protection": "enabled",
"tags": {
"tag0": "value0"
}
}
```
The response includes two status fields:
| Field | Description |
| :----------------------------------------------- | :------------------------------------------------------------------------- |
| **`status.state`** | Overall index status (for example, `Initializing`, `Ready`, `Terminating`) |
| **`spec.serverless.read_capacity.status.state`** | Read capacity status (`Migrating`, `Scaling`, `Ready`, `Error`) |
When changing node types, shards, or replicas, monitor the read capacity status (`spec.serverless.read_capacity.status.state`). Possible values:
| State | Description |
| :-------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`Ready`** | The change is complete and the index is ready to serve queries at full capacity. |
| **`Scaling`** | A change to the number of shards or replicas is in progress. |
| **`Migrating`** | A change to the node type or read capacity mode is in progress. |
| **`Error`** | The operation failed. For migrations to dedicated, this typically means you didn't allocate enough shards for your index size. Check `error_message` for details, and retry with more shards. |
During changes to shards, replicas, and node type, the index-level status (`status.state`) remains `Ready`. This is because the index can handle reads and writes while its dedicated read capacity scales.
Configuration change limits:
* You can make one configuration change every ten minutes, but you can batch multiple changes (node type, shards, and replicas) in a single request.
* A new configuration change can only be initiated after the previous configuration change has completed.
* Each configuration change can take up to 30 minutes to complete.
* Read and write operations continue normally during configuration changes.
You cannot directly convert a dedicated read nodes index to on-demand with the API. Instead, you can migrate your data by [backing up your index](/guides/manage-data/back-up-an-index) and then [restoring it into a new serverless index](/guides/manage-data/restore-an-index) without dedicated read nodes enabled.
1. [Create a backup](/guides/manage-data/back-up-an-index) of your dedicated read nodes index.
2. [Create a new index from the backup](/guides/manage-data/restore-an-index), without specifying dedicated read node configuration.
3. Verify the new on-demand index and update your application to use it.
4. Delete the old dedicated read nodes index.
If you have concerns or need assistance, [contact support](https://app.pinecone.io/organizations/-/settings/support/ticket).
## Limits
The following limits apply to dedicated read nodes:
Dedicated read nodes indexes are not subject to [read-operation rate limits](/reference/api/database-limits#rate-limits), like on-demand indexes are. However, if your query rate exceeds the compute capacity of your index, you may observe decreased query throughput. In such cases, consider [adding replicas](#add-or-remove-replicas) to increase compute resources, or use [query-time search parameters](#query-time-search-parameters) to reduce per-query compute and increase throughput without adding replicas.
On dedicated read nodes indexes, write operations (upsert, update, delete) have the same [rate limits](/reference/api/database-limits#rate-limits) as on-demand indexes.
Writes that would cause your index to exceed its storage capacity are blocked. In such cases, consider [adding shards](#add-or-remove-shards) to increase available storage. To determine how close to the write limit you are, [check index fullness](#monitor-index-fullness).
Currently, dedicated read nodes indexes only support a single namespace. However, multi-namespace support is coming soon. For early access, [contact support](https://app.pinecone.io/organizations/-/settings/support/ticket).
**Shards**
The minimum number of [shards](#shards) per index is 1.
**Replicas**
The minimum number of [replicas](#replicas) per index is 0, which [pauses the index](#pause-an-index).
**Nodes**
The maximum number of [nodes](#node-types) per project is 20. This is a **project** limit, not an index limit.
To calculate your total node count, multiply `shards × replicas` for each of your project's indexes, and then sum the results. This total must not exceed 20. For example, if you have two indexes that each have two shards and three replicas, your total node count is `(2 × 3) + (2 × 3) = 12` nodes.
To increase your project's node limit, [contact support](https://app.pinecone.io/organizations/-/settings/support/ticket).
Configuration change limits:
* You can make one configuration change every ten minutes, but you can batch multiple changes (node type, shards, and replicas) in a single request.
* A new configuration change can only be initiated after the previous configuration change has completed.
* Each configuration change can take up to 30 minutes to complete.
* Read and write operations continue normally during configuration changes.
`memoryFullness` is an approximation and doesn't yet account for metadata. For more information, see [Index fullness](#index-fullness).
To migrate an index from dedicated to on-demand, [contact support](https://app.pinecone.io/organizations/-/settings/support/ticket). This cannot be done with the API.
## Cost
For the latest pricing information, see the [Pinecone pricing page](https://www.pinecone.io/pricing/).
The cost of an index has three components: read costs, write costs, and storage costs.
On-demand and dedicated read nodes share infrastructure for writes and storage, so these costs are the same. However, dedicated read nodes provision dedicated hardware for read operations (query, fetch, list), which changes how read costs are calculated.
| Cost component | On-demand | Dedicated read nodes |
| :---------------- | :------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------- |
| **Read costs** | [Usage-based](/guides/manage-cost/understanding-cost#read-units): 1 RU per 1 GB namespace size per query | Fixed hourly rate: Based on [node type](#node-types), [shards](#shards), and [replicas](#replicas) |
| **Write costs** | [Usage-based](/guides/manage-cost/understanding-cost#write-units) | [Usage-based](/guides/manage-cost/understanding-cost#write-units) (same as on-demand) |
| **Storage costs** | [Usage-based](/guides/manage-cost/understanding-cost#storage) | [Usage-based](/guides/manage-cost/understanding-cost#storage) (same as on-demand) |
If you use a hosted model for search or reranking, there are additional [inference costs](https://www.pinecone.io/pricing).
To calculate the total cost of a dedicated read nodes index, use this formula:
```
(Node rate × shards × replicas) + storage costs + write costs
```
| Term | Description |
| :---------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Node rate** | Monthly rate for the [node type](#node-types) (`b1` or `t1`), which varies by cloud region. See [Pinecone pricing](https://www.pinecone.io/pricing/). |
| **Shards** | Number of [shards](#shards) allocated |
| **Replicas** | Number of [replicas](#replicas) allocated |
| **Storage costs** | [Usage-based](/guides/manage-cost/understanding-cost#storage), same as on-demand |
| **Write costs** | [Usage-based](/guides/manage-cost/understanding-cost#write-units), same as on-demand |
For help estimating costs, use the [Pinecone pricing calculator](https://www.pinecone.io/pricing/estimate/) or [contact us](https://www.pinecone.io/contact/).
**Example:** If the rate for `b1` nodes on `aws-us-east-1` is \$336.42/month (\$0.46/hour), an index with two shards and two replicas would cost:
```
336.42 × 2 × 2 = $1,345.68/month, plus storage and write costs
```
# Implement multitenancy
Source: https://docs.pinecone.io/guides/index-data/implement-multitenancy
Implement multitenancy in Pinecone with one namespace per tenant on a serverless index to isolate customer data for SaaS RAG or semantic search apps.
[Multitenancy](https://en.wikipedia.org/wiki/Multitenancy) is a software architecture where a single instance of a system serves multiple customers, or tenants, while ensuring data isolation between them for privacy and security.
This page shows you how to implement multitenancy in Pinecone using a **serverless index with one namespace per tenant**.
For design guidance on choosing between namespaces, metadata filtering, and other approaches, see [Design for multi-tenancy](/guides/index-data/data-modeling#design-for-multi-tenancy).
[Namespaces per serverless index](/reference/api/database-limits#namespaces-per-serverless-index) vary by plan. On the Standard and Enterprise plans, Pinecone can accommodate million-scale namespaces and beyond for specific use cases. If your application requires more than 100,000 namespaces, [contact Support](https://app.pinecone.io/organizations/-/settings/support/ticket).
## How it works
In Pinecone, an [index](/guides/index-data/indexing-overview) is the highest-level organizational unit of data, where you define the dimension of vectors to be stored in the index and the measure of similarity to be used when querying the index.
Within an index, records are stored in [namespaces](/guides/index-data/indexing-overview#namespaces), and all [upserts](/guides/index-data/upsert-data), [queries](/guides/search/search-overview), and other data read and write operations always target one namespace.
This structure makes it easy to implement multitenancy. For example, for an AI-powered SaaS application where you need to isolate the data of each customer, you would assign each customer to a namespace and target their writes and queries to that namespace (diagram above).
In cases where you have different workload patterns (e.g., RAG and semantic search), you would use a different index for each workload, with one namespace per customer in each index:
* **Tenant isolation:** In the [serverless architecture](/guides/get-started/database-architecture), each namespace is stored separately, so using namespaces provides physical isolation of data between tenants/customers. This reduces the risk of application bugs that could query the wrong tenant's data.
* **No noisy neighbors:** Reads and writes always target a single namespace, so the behavior of one tenant/customer does not affect other tenants/customers.
* **No maintenance effort:** Serverless indexes scale automatically based on usage; you don't configure or manage any compute or storage resources.
* **Cost efficiency:** Query cost is based on namespace size (1 RU per 1 GB). With 100 tenants of 1 GB each, querying one tenant's namespace costs 1 RU. Using metadata filtering in a single 100 GB namespace would cost 100 RUs for the same query, because it scans all data regardless of filters.
* **Simple tenant offboarding:** To offboard a tenant/customer, you just [delete the relevant namespace](/guides/manage-data/delete-data#delete-all-records-from-a-namespace). This is a lightweight and almost instant operation.
## 1. Create a serverless index
Based on a [breakthrough architecture](/guides/get-started/database-architecture), serverless indexes scale automatically based on usage, and you pay only for the amount of data stored and operations performed. Combined with the isolation of tenant data using namespaces (next step), serverless indexes are ideal for multitenant use cases.
To [create a serverless index](/guides/index-data/create-an-index#create-a-serverless-index), use the `spec` parameter to define the cloud and region where the index should be deployed. For Python, you also need to import the `ServerlessSpec` class.
```Python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
from pinecone import ServerlessSpec
pc = Pinecone(api_key="YOUR_API_KEY")
pc.create_index(
name="multitenant-app",
dimension=8,
metric="cosine",
spec=ServerlessSpec(
cloud="aws",
region="us-east-1"
)
)
```
```JavaScript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({
apiKey: 'YOUR_API_KEY'
});
await pc.createIndex({
name: 'multitenant-app',
dimension: 8,
metric: 'cosine',
spec: {
serverless: {
cloud: 'aws',
region: 'us-east-1'
}
}
});
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
public class CreateServerlessIndexExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
pc.createServerlessIndex("multitenant-app", "cosine", 8, "aws", "us-east-1");
}
}
```
```go Go theme={null}
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func prettifyStruct(obj interface{}) string {
bytes, _ := json.MarshalIndent(obj, "", " ")
return string(bytes)
}
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
// Serverless index
indexName := "multi-tenant-app"
vectorType := "dense"
dimension := int32(8)
metric := pinecone.Cosine
deletionProtection := pinecone.DeletionProtectionDisabled
idx, err := pc.CreateServerlessIndex(ctx, &pinecone.CreateServerlessIndexRequest{
Name: indexName,
VectorType: &vectorType,
Dimension: &dimension,
Metric: &metric,
Cloud: pinecone.Aws,
Region: "us-east-1",
DeletionProtection: &deletionProtection,
})
if err != nil {
log.Fatalf("Failed to create serverless index: %v", err)
} else {
fmt.Printf("Successfully created serverless index: %v", idx.Name)
}
}
```
```bash curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -s "https://api.pinecone.io/indexes" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"name": "multitenant-app",
"dimension": 8,
"metric": "cosine",
"spec": {
"serverless": {
"cloud": "aws",
"region": "us-east-1"
}
}
}'
```
## 2. Isolate tenant data
In a multitenant solution, you need to isolate data between tenants. To achieve this in Pinecone, use one namespace per tenant. In the [serverless architecture](/guides/get-started/database-architecture), each namespace is stored separately, so this approach ensures physical isolation of each tenant's data.
To [create a namespace for a tenant](/guides/index-data/indexing-overview#namespaces#creating-a-namespace), specify the `namespace` parameter when first [upserting](/guides/index-data/upsert-data) the tenant's records. For example, the following code upserts records for `tenant1` and `tenant2` into the `multitenant-app` index:
```Python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
index = pc.Index("multitenant-app")
index.upsert(
vectors=[
{"id": "A", "values": [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]},
{"id": "B", "values": [0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2]},
{"id": "C", "values": [0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3]},
{"id": "D", "values": [0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4]}
],
namespace="tenant1"
)
index.upsert(
vectors=[
{"id": "E", "values": [0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5]},
{"id": "F", "values": [0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6]},
{"id": "G", "values": [0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7]},
{"id": "H", "values": [0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8]}
],
namespace="tenant2"
)
```
```JavaScript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({ apiKey: "YOUR_API_KEY" });
const index = pc.index("multitenant-app");
await index.namespace("tenant1").upsert([
{
"id": "A",
"values": [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]
},
{
"id": "B",
"values": [0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2]
},
{
"id": "C",
"values": [0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3]
},
{
"id": "D",
"values": [0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4]
}
]);
await index.namespace("tenant2").upsert([
{
"id": "E",
"values": [0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5]
},
{
"id": "F",
"values": [0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6]
},
{
"id": "G",
"values": [0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7]
},
{
"id": "H",
"values": [0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8]
}
]);
```
```java Java theme={null}
import io.pinecone.clients.Index;
import io.pinecone.clients.Pinecone;
import java.util.Arrays;
import java.util.List;
public class UpsertExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
String indexName = "multitenant-app";
Index index = pc.getIndexConnection(indexName);
List values1 = Arrays.asList(0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f);
List values2 = Arrays.asList(0.2f, 0.2f, 0.2f, 0.2f, 0.2f, 0.2f, 0.2f, 0.2f);
List values3 = Arrays.asList(0.3f, 0.3f, 0.3f, 0.3f, 0.3f, 0.3f, 0.3f, 0.3f);
List values4 = Arrays.asList(0.4f, 0.4f, 0.4f, 0.4f, 0.4f, 0.4f, 0.4f, 0.4f);
List values5 = Arrays.asList(0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f);
List values6 = Arrays.asList(0.6f, 0.6f, 0.6f, 0.6f, 0.6f, 0.6f, 0.6f, 0.6f);
List values7 = Arrays.asList(0.7f, 0.7f, 0.7f, 0.7f, 0.7f, 0.7f, 0.7f, 0.7f);
List values8 = Arrays.asList(0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f);
index.upsert("A", values1, "tenant1");
index.upsert("B", values2, "tenant1");
index.upsert("C", values3, "tenant1");
index.upsert("D", values4, "tenant1");
index.upsert("E", values5, "tenant2");
index.upsert("F", values6, "tenant2");
index.upsert("G", values7, "tenant2");
index.upsert("H", values8, "tenant2");
}
}
```
```go Go theme={null}
// Add to the main function:
idx, err := pc.DescribeIndex(ctx, indexName)
if err != nil {
log.Fatalf("Failed to describe index \"%v\": %v", idx.Name, err)
}
idxConnection1, err := pc.Index(pinecone.NewIndexConnParams{Host: idx.Host, Namespace: "tenant1"})
if err != nil {
log.Fatalf("Failed to create IndexConnection1 for Host %v: %v", idx.Host, err)
}
// This reuses the gRPC connection of idxConnection1 while targeting a different namespace
idxConnection2 := idxConnection1.WithNamespace("tenant2")
vectors1 := []*pinecone.Vector{
{
Id: "A",
Values: []float32{0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1},
},
{
Id: "B",
Values: []float32{0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2},
},
{
Id: "C",
Values: []float32{0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3},
},
{
Id: "D",
Values: []float32{0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4},
},
}
vectors2 := []*pinecone.Vector{
{
Id: "E",
Values: []float32{0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5},
},
{
Id: "F",
Values: []float32{0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6},
},
{
Id: "G",
Values: []float32{0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7},
},
{
Id: "H",
Values: []float32{0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8},
},
}
count1, err := idxConnection1.UpsertVectors(ctx, vectors1)
if err != nil {
log.Fatalf("Failed to upsert vectors: %v", err)
} else {
fmt.Printf("Successfully upserted %d vector(s)!\n", count1)
}
count2, err := idxConnection2.UpsertVectors(ctx, vectors2)
if err != nil {
log.Fatalf("Failed to upsert vectors: %v", err)
} else {
fmt.Printf("Successfully upserted %d vector(s)!\n", count2)
}
```
```bash curl theme={null}
# The `POST` requests below uses the unique endpoint for an index.
# See https://docs.pinecone.io/guides/manage-data/target-an-index for details.
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
curl "https://$INDEX_HOST/vectors/upsert" \
-H "Api-Key: $PINECONE_API_KEY" \
-H 'Content-Type: application/json' \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"vectors": [
{
"id": "A",
"values": [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]
},
{
"id": "B",
"values": [0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2]
},
{
"id": "C",
"values": [0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3]
},
{
"id": "D",
"values": [0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4]
}
],
"namespace": "tenant1"
}'
curl "https://$INDEX_HOST/vectors/upsert" \
-H "Api-Key: $PINECONE_API_KEY" \
-H 'Content-Type: application/json' \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"vectors": [
{
"id": "E",
"values": [0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5]
},
{
"id": "F",
"values": [0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6]
},
{
"id": "G",
"values": [0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7]
},
{
"id": "H",
"values": [0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8]
}
],
"namespace": "tenant2"
}'
```
When upserting additional records for a tenant, or when [updating](/guides/manage-data/update-data) or [deleting](/guides/manage-data/delete-data) records for a tenant, specify the tenant's `namespace`. For example, the following code updates the dense vector value of record `A` in `tenant1`:
```Python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
index = pc.Index("multitenant-app")
index.update(id="A", values=[0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8], namespace="tenant1")
```
```JavaScript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({ apiKey: "YOUR_API_KEY" });
const index = pc.index("multitenant-app");
await index.namespace('tenant1').update({
id: 'A',
values: [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8]
});
```
```java Java theme={null}
import io.pinecone.clients.Index;
import io.pinecone.clients.Pinecone;
import io.pinecone.proto.UpdateResponse;
import java.util.Arrays;
import java.util.List;
public class UpdateExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
Index index = pc.getIndexConnection("multitenant-app");
List values = Arrays.asList(0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f);
UpdateResponse updateResponse = index.update("A", values, null, "tenant1", null, null);
System.out.println(updateResponse);
}
}
```
```go Go theme={null}
// Add to the main function:
idxConn1.UpdateVector(ctx, &pinecone.UpdateVectorRequest{
Id: "A",
Values: []float32{0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8},
})
if err != nil {
log.Fatalf("Failed to update vector with ID %v: %v", id, err)
}
```
```bash curl theme={null}
# The `POST` request below uses the unique endpoint for an index.
# See https://docs.pinecone.io/guides/manage-data/target-an-index for details.
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
curl "https://$INDEX_HOST/vectors/update" \
-H "Api-Key: $PINECONE_API_KEY" \
-H 'Content-Type: application/json' \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"id": "A",
"values": [01., 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8],
"namespace": "tenant1"
}'
```
## 3. Query tenant data
In a multitenant solution, you need to ensure that the queries of one tenant do not affect the experience of other tenants/customers. To achieve this in Pinecone, target each tenant's [queries](/guides/search/search-overview) at the namespace for the tenant.
For example, the following code queries only `tenant2` for the 3 vectors that are most similar to an example query vector:
```python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
index = pc.Index("multitenant-app")
query_results = index.query(
namespace="tenant2",
vector=[0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7],
top_k=3,
include_values=True
)
print(query_results)
# Returns:
# {'matches': [{'id': 'F',
# 'score': 1.00000012,
# 'values': [0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6]},
# {'id': 'G',
# 'score': 1.0,
# 'values': [0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7]},
# {'id': 'E',
# 'score': 1.0,
# 'values': [0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5]}],
# 'namespace': 'tenant2',
# 'usage': {'read_units': 6}}
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({ apiKey: "YOUR_API_KEY" });
const index = pc.index("multitenant-app");
const queryResponse = await index.namespace("tenant2").query({
topK: 3,
vector: [0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7],
includeValues: true
});
console.log(queryResponse);
// Returns:
{
"matches": [
{
"id": "F",
"score": 1.00000012,
"values": [
0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6
]
},
{
"id": "E",
"score": 1,
"values": [ 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5
]
},
{
"id": "G",
"score": 1,
"values": [
0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7
]
}
],
"namespace": "tenant2",
"usage": {
"readUnits": 6
}
}
```
```java Java theme={null}
import io.pinecone.clients.Index;
import io.pinecone.clients.Pinecone;
import io.pinecone.unsigned_indices_model.QueryResponseWithUnsignedIndices;
import java.util.Arrays;
import java.util.List;
public class QueryExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
String indexName = "multitenant-app";
Index index = pc.getIndexConnection(indexName);
List queryVector = Arrays.asList(0.7f, 0.7f, 0.7f, 0.7f, 0.7f, 0.7f, 0.7f, 0.7f);
QueryResponseWithUnsignedIndices queryResponse = index.query(3, queryVector2, null, null, null, "tenant2", null, true, false);
System.out.println(queryResponse);
}
}
// Results:
// class QueryResponseWithUnsignedIndices {
// matches: [ScoredVectorWithUnsignedIndices {
// score: 1.00000012
// id: F
// values: [0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6]
// metadata:
// sparseValuesWithUnsignedIndices: SparseValuesWithUnsignedIndices {
// indicesWithUnsigned32Int: []
// values: []
// }
// }, ScoredVectorWithUnsignedIndices {
// score: 1
// id: E
// values: [0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5]
// metadata:
// sparseValuesWithUnsignedIndices: SparseValuesWithUnsignedIndices {
// indicesWithUnsigned32Int: []
// values: []
// }
// }, ScoredVectorWithUnsignedIndices {
// score: 0.07999992
// id: G
// values: [0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7]
// metadata:
// sparseValuesWithUnsignedIndices: SparseValuesWithUnsignedIndices {
// indicesWithUnsigned32Int: []
// values: []
// }
// }]
// namespace: tenant2
// usage: read_units: 6
// }
```
```go Go theme={null}
// Add to the main function:
queryVector := []float32{0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7}
res, err := idxConnection2.QueryByVectorValues(ctx, &pinecone.QueryByVectorValuesRequest{
Vector: queryVector,
TopK: 3,
IncludeValues: true,
})
if err != nil {
log.Fatalf("Error encountered when querying by vector: %v", err)
} else {
fmt.Printf(prettifyStruct(res))
}
// Returns:
// {
// "matches": [
// {
// "vector": {
// "id": "F",
// "values": [
// 0.6,
// 0.6,
// 0.6,
// 0.6,
// 0.6,
// 0.6,
// 0.6,
// 0.6
// ]
// },
// "score": 1.0000001
// },
// {
// "vector": {
// "id": "G",
// "values": [
// 0.7,
// 0.7,
// 0.7,
// 0.7,
// 0.7,
// 0.7,
// 0.7,
// 0.7
// ]
// },
// "score": 1
// },
// {
// "vector": {
// "id": "H",
// "values": [
// 0.8,
// 0.8,
// 0.8,
// 0.8,
// 0.8,
// 0.8,
// 0.8,
// 0.8
// ]
// },
// "score": 1
// }
// ],
// "usage": {
// "read_units": 6
// }
// }
```
```shell curl theme={null}
# The `POST` requests below uses the unique endpoint for an index.
# See https://docs.pinecone.io/guides/manage-data/target-an-index for details.
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
curl "https://$INDEX_HOST/query" \
-H "Api-Key: $PINECONE_API_KEY" \
-H 'Content-Type: application/json' \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"namespace": "tenant2",
"vector": [0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7],
"topK": 3,
"includeValues": true
}'
#
# Output:
# {
# "matches": [
# {
# "id": "F",
# "score": 1.00000012,
# "values": [0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6]
# },
# {
# "id": "E",
# "score": 1,
# "values": [0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5]
# },
# {
# "id": "G",
# "score": 1,
# "values": [0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7]
# }
# ],
# "namespace": "tenant2",
# "usage": {"read_units": 6}
# }
```
## 4. Offboard a tenant
In a multitenant solution, you also need it to be quick and easy to offboard a tenant and delete all of its records. To achieve this in Pinecone, you just [delete the namespace](/guides/manage-data/delete-data#delete-an-entire-namespace) for the specific tenant.
For example, the following code deletes the namespace and all records for `tenant1`:
```Python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
index = pc.Index("multitenant-app")
index.delete(delete_all=True, namespace='tenant1')
```
```JavaScript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({ apiKey: "YOUR_API_KEY" });
const index = pc.index("multitenant-app");
await index.namespace('tenant1').deleteAll();
```
```java Java theme={null}
import io.pinecone.clients.Index;
import io.pinecone.clients.Pinecone;
public class DeleteVectorsExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
Index index = pc.getIndexConnection("multitenant-app");
index.deleteAll("tenant1");
}
}
```
```go Go theme={null}
// Add to the main function:
idxConnection1.DeleteAllVectorsInNamespace(ctx)
if err != nil {
log.Fatalf("Failed to delete vectors in namespace \"%v\": %v", idxConnection2.Namespace, err)
}
```
```bash curl theme={null}
# The `POST` request below uses the unique endpoint for an index.
# See https://docs.pinecone.io/guides/manage-data/target-an-index for details.
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
curl "https://$INDEX_HOST/vectors/delete" \
-H "Api-Key: $PINECONE_API_KEY" \
-H 'Content-Type: application/json' \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"deleteAll": true,
"namespace": "tenant1"
}
'
```
## Alternative: Metadata filtering
When tenant isolation is not a strict requirement, or when you need to query across multiple tenants simultaneously, you can store all records in a single namespace and use metadata fields to assign records to tenants/customers. At query time, you can then [filter by metadata](/guides/index-data/indexing-overview#metadata).
This approach has significant performance and cost tradeoffs compared to using namespaces:
* Higher query costs: Queries scan the entire namespace regardless of filters, so you pay for scanning all tenants' data even though results are filtered to one tenant.
* Slower performance: Large namespaces increase query latency, and large filters add network overhead on the request side.
* Filter size limits: Each `$in` or `$nin` operator is limited to 10,000 values. Exceeding this limit will cause requests to fail. See [Metadata filter limits](/reference/api/database-limits#metadata-filter-limits).
Anti-pattern: Avoid filtering by large lists of individual user IDs. Instead, use access control groups (organization, project, role), namespaces, or post-filter client-side (for semantic search).
For detailed guidance on choosing between namespaces and metadata filtering, see [Design for multi-tenancy](/guides/index-data/data-modeling#design-for-multi-tenancy).
For more background on this approach, see [Multitenancy in Vector Databases](https://www.pinecone.io/learn/series/vector-databases-in-production-for-busy-engineers/vector-database-multi-tenancy/).
# Import records
Source: https://docs.pinecone.io/guides/index-data/import-data
Import large datasets efficiently from Amazon S3, Google Cloud Storage, or Azure Blob Storage into Pinecone serverless indexes using object storage.
Importing from object storage is the most efficient and cost-effective way to load large numbers of records into an index.
To run through this guide in your browser, see the [Bulk import colab notebook](https://colab.research.google.com/github/pinecone-io/examples/blob/master/docs/pinecone-import.ipynb).
This feature is available on [Standard and Enterprise plans](https://www.pinecone.io/pricing/).
## Before you import
Before you can import records, ensure you have a serverless index, a storage integration, and data formatted in a Parquet file and uploaded to an Amazon S3 bucket, Google Cloud Storage bucket, or Azure Blob Storage container.
### Create an index
[Create a serverless index](/guides/index-data/create-an-index) for your data.
Be sure to create your index on a cloud that supports importing from the object storage you want to use:
| | …to an **AWS** index | …to a **GCP** index | …to an **Azure** index |
| ------------------------------------- | :------------------: | :-----------------: | :--------------------: |
| Import from **AWS S3**… | ✅ | ❌ | ❌ |
| Import from **Google Cloud Storage**… | ✅ | ✅ | ✅ |
| Import from **Azure Blob Storage**… | ✅ | ✅ | ✅ |
### Add a storage integration
To import records from a public data source, a storage integration is not required. However, to import records from a secure data source, you must create an integration to allow Pinecone access to data in your object storage. See the following guides:
* [Integrate with Amazon S3](/guides/operations/integrations/integrate-with-amazon-s3)
* [Integrate with Google Cloud Storage](/guides/operations/integrations/integrate-with-google-cloud-storage)
* [Integrate with Azure Blob Storage](/guides/operations/integrations/integrate-with-azure-blob-storage)
### Prepare your data
1. In your Amazon S3 bucket, Google Cloud Storage bucket, or Azure Blob Storage container, create an import directory containing a subdirectory for each namespace you want to import into. The namespaces must not yet exist in your index.
For example, to import data into the namespaces `example_namespace1` and `example_namespace2`, your directory structure would look like this:
```
/
--//
----/example_namespace1/
----/example_namespace2/
```
To import into the default namespace, use a subdirectory called `__default__`. The default namespace must be empty.
2. For each namespace, create one or more Parquet files defining the records to import.
Parquet files must contain specific columns, depending on the index type:
To import into a namespace in an [index of dense vectors](/guides/index-data/indexing-overview#indexes-with-dense-vectors), the Parquet file must contain the following columns:
| Column name | Parquet type | Description |
| ----------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `id` | `STRING` | Required. The unique [identifier for each record](/guides/get-started/concepts#record-id). |
| `values` | `LIST` | Required. A list of floating-point values that make up the [dense vector embedding](/guides/get-started/concepts#dense-vector). |
| `metadata` | `STRING` | Optional. Additional [metadata](/guides/get-started/concepts#metadata) for each record. To omit from specific rows, use `NULL`. |
Additional columns in the Parquet file are silently ignored during import; only `id`, `values`, and `metadata` are processed.
For example:
```parquet theme={null}
id | values | metadata
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1 | [ 3.82 2.48 -4.15 ... ] | {"year": 1984, "month": 6, "source": "source1", "title": "Example1", "text": "When ..."}
2 | [ 1.82 3.48 -2.15 ... ] | {"year": 1990, "month": 4, "source": "source2", "title": "Example2", "text": "Who ..."}
```
To import into a namespace in an [index of sparse vectors](/guides/index-data/indexing-overview#indexes-with-sparse-vectors), the Parquet file must contain the following columns:
| Column name | Parquet type | Description |
| --------------- | ----------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id` | `STRING` | Required. The unique [identifier for each record](/guides/get-started/concepts#record-id). |
| `sparse_values` | `STRUCT, values: LIST>` | Required. A list of floating-point values (sparse values) and a list of integer values (sparse indices) that make up the [sparse vector embedding](/guides/get-started/concepts#sparse-vector). |
| `metadata` | `STRING` | Optional. Additional [metadata](/guides/get-started/concepts#metadata) for each record. To omit from specific rows, use `NULL`. |
Additional columns in the Parquet file are silently ignored during import; only `id`, `sparse_values`, and `metadata` are processed.
For example:
```parquet theme={null}
id | sparse_values | metadata
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1 | {"indices": [ 822745112 1009084850 1221765879 ... ], "values": [1.7958984 0.41577148 2.828125 ...]} | {"year": 1984, "month": 6, "source": "source1", "title": "Example1", "text": "When ..."}
2 | {"indices": [ 504939989 1293001993 3201939490 ... ], "values": [1.4383747 0.72849722 1.384775 ...]} | {"year": 1990, "month": 4, "source": "source2", "title": "Example2", "text": "Who ..."}
```
To import into a namespace in an [index with both dense and sparse vectors](/guides/search/hybrid-search#use-a-single-index-for-dense-and-sparse-vectors), the Parquet file must contain the following columns:
| Column name | Parquet type | Description |
| --------------- | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id` | `STRING` | Required. The unique [identifier for each record](/guides/get-started/concepts#record-id). |
| `values` | `LIST` | Required. A list of floating-point values that make up the [dense vector embedding](/guides/get-started/concepts#dense-vector). |
| `sparse_values` | `STRUCT, values: LIST>` | Optional. A list of floating-point values that make up the [sparse vector embedding](/guides/get-started/concepts#sparse-vector). To omit from specific rows, use `NULL`. |
| `metadata` | `STRING` | Optional. Additional [metadata](/guides/get-started/concepts#metadata) for each record. To omit from specific rows, use `NULL`. |
Additional columns in the Parquet file are silently ignored during import; only `id`, `values`, `sparse_values`, and `metadata` are processed.
For example:
```parquet theme={null}
id | values | sparse_values | metadata
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1 | [ 3.82 2.48 -4.15 ... ] | {"indices": [1082468256, 1009084850, 1221765879, ...], "values": [2.0, 3.0, 4.0, ...]} | {"year": 1984, "month": 6, "source": "source1", "title": "Example1", "text": "When ..."}
2 | [ 1.82 3.48 -2.15 ... ] | {"indices": [2225824123, 1293001993, 3201939490, ...], "values": [5.0, 2.0, 3.0, ...]} | {"year": 1990, "month": 4, "source": "source2", "title": "Example2", "text": "Who ..."}
```
3. Upload the Parquet files into the relevant subdirectory.
For example, if you have subdirectories for the namespaces `example_namespace1` and `example_namespace2` and upload 4 Parquet files into each, your directory structure would look as follows after the upload:
```
/
--//
----/example_namespace1/
------0.parquet
------1.parquet
------2.parquet
------3.parquet
----/example_namespace2/
------4.parquet
------5.parquet
------6.parquet
------7.parquet
```
## Import records into an index
Review [import limits](#import-limits) before starting an import.
This guide covers importing Parquet files into indexes **without** a schema definition. Indexes with document schemas import [JSONL files](/guides/search/full-text-search#bulk-import) instead. Semantic-text (auto-embedded) fields are not yet supported in document schemas.
Use the [`start_import`](/reference/api/latest/data-plane/start_import) operation to start an asynchronous import of vectors from object storage into an index.
* For `uri`, specify the URI of the bucket and import directory containing the namespaces and Parquet files you want to import. For example:
* Amazon S3: `s3://BUCKET_NAME/IMPORT_DIR`
* Google Cloud Storage: `gs://BUCKET_NAME/IMPORT_DIR`
* Azure Blob Storage: `https://STORAGE_ACCOUNT.blob.core.windows.net/CONTAINER_NAME/IMPORT_DIR`
* For `integration_id`, specify the Integration ID of the Amazon S3, Google Cloud Storage, or Azure Blob Storage integration you created. The ID is found on the [Storage integrations](https://app.pinecone.io/organizations/-/projects/-/storage) page of the Pinecone console.
An Integration ID is not needed to import from a public bucket.
* For `error_mode`, use `continue` or `abort`.
* With `abort`, the operation stops if any records fail to import.
* With `continue`, the operation continues on error, but there is not any notification about which records, if any, failed to import. To see how many records were successfully imported, use the [describe an import](#describe-an-import) operation.
```python Python theme={null}
from pinecone import Pinecone, ImportErrorMode
pc = Pinecone(api_key="YOUR_API_KEY")
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
index = pc.Index(host="INDEX_HOST")
root = "s3://example_bucket/import"
index.start_import(
uri=root,
integration_id="a12b3d4c-47d2-492c-a97a-dd98c8dbefde", # Optional for public buckets
error_mode=ImportErrorMode.CONTINUE # or ImportErrorMode.ABORT
)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' });
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
const index = pc.index("INDEX_NAME", "INDEX_HOST")
const storageURI = 's3://example_bucket/import';
const errorMode = 'continue'; // or 'abort'
const integrationID = 'a12b3d4c-47d2-492c-a97a-dd98c8dbefde'; // Optional for public buckets
await index.startImport(storageURI, errorMode, integrationID);
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import io.pinecone.clients.AsyncIndex;
import org.openapitools.db_data.client.ApiException;
import org.openapitools.db_data.client.model.ImportErrorMode;
import org.openapitools.db_data.client.model.StartImportResponse;
public class StartImport {
public static void main(String[] args) throws ApiException {
// Initialize a Pinecone client with your API key
Pinecone pinecone = new Pinecone.Builder("YOUR_API_KEY").build();
// Get async imports connection object
AsyncIndex asyncIndex = pinecone.getAsyncIndexConnection("docs-example");
// s3 uri
String uri = "s3://example_bucket/import";
// Integration ID (optional for public buckets)
String integrationId = "a12b3d4c-47d2-492c-a97a-dd98c8dbefde";
// Start an import
StartImportResponse response = asyncIndex.startImport(uri, integrationId, ImportErrorMode.OnErrorEnum.CONTINUE);
}
}
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
idxConnection, err := pc.Index(pinecone.NewIndexConnParams{Host: "INDEX_HOST"})
if err != nil {
log.Fatalf("Failed to create IndexConnection for Host: %v", err)
}
uri := "s3://example_bucket/import"
errorMode := "continue" // or "abort"
importRes, err := idxConnection.StartImport(ctx, uri, nil, (*pinecone.ImportErrorMode)(&errorMode))
if err != nil {
log.Fatalf("Failed to start import: %v", err)
}
fmt.Printf("Import started with ID: %s", importRes.Id)
}
```
```bash curl theme={null}
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
curl "https://$INDEX_HOST/bulk/imports" \
-H 'Api-Key: $YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-H 'X-Pinecone-Api-Version: 2025-10' \
-d '{
"integrationId": "a12b3d4c-47d2-492c-a97a-dd98c8dbefde",
"uri": "s3://example_bucket/import",
"errorMode": {
"onError": "continue"
}
}'
```
The response contains an `id` that you can use to [check the status of the import](#list-imports):
```json Response theme={null}
{
"id": "101"
}
```
Once all the data is loaded, the [index builder](/guides/get-started/database-architecture#index-builder) indexes the records, which usually takes at least 10 minutes. During this indexing process, the expected job status is `InProgress`, but `100.0` percent complete. Once all the imported records are indexed and fully available for querying, the import operation is set to `Completed`. If you cancel the import before it finishes, the status changes to `Cancelled`.
You can start a new import using the [Pinecone console](https://app.pinecone.io/organizations/-/projects/-/indexes). Find the index you want to import into, and click the **ellipsis (...) menu > Import data**.
## Track import progress
The amount of time required for an import depends on various factors, including:
* The number of records to import
* The number of namespaces to import, and the the number of records in each
* The total size (in bytes) of the import
To track an import's progress, check its status bar in the [Pinecone console](https://app.pinecone.io/organizations/-/projects/-/import) or use the [`describe_import`](/reference/api/latest/data-plane/describe_import) operation with the import ID:
```python Python theme={null}
from pinecone import Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
index = pc.Index(host="INDEX_HOST")
index.describe_import(id="101")
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' });
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
const index = pc.index("INDEX_NAME", "INDEX_HOST")
const results = await index.describeImport(id='101');
console.log(results);
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import io.pinecone.clients.AsyncIndex;
import org.openapitools.db_data.client.ApiException;
import org.openapitools.db_data.client.model.ImportModel;
public class DescribeImport {
public static void main(String[] args) throws ApiException {
// Initialize a Pinecone client with your API key
Pinecone pinecone = new Pinecone.Builder("YOUR_API_KEY").build();
// Get async imports connection object
AsyncIndex asyncIndex = pinecone.getAsyncIndexConnection("docs-example");
// Describe import
ImportModel importDetails = asyncIndex.describeImport("101");
System.out.println(importDetails);
}
}
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
idxConnection, err := pc.Index(pinecone.NewIndexConnParams{Host: "INDEX_HOST"})
if err != nil {
log.Fatalf("Failed to create IndexConnection for Host: %v", err)
}
importID := "101"
importDesc, err := idxConnection.DescribeImport(ctx, importID)
if err != nil {
log.Fatalf("Failed to describe import: %s - %v", importID, err)
}
fmt.Printf("Import ID: %s, Status: %s", importDesc.Id, importDesc.Status)
}
```
```bash curl theme={null}
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
curl -X GET "https://{INDEX_HOST}/bulk/imports/101" \
-H 'Api-Key: $YOUR_API_KEY' \
-H 'X-Pinecone-Api-Version: 2025-10'
```
The response contains the import details, including the import `status`, `percent_complete`, and `records_imported`:
```json Response theme={null}
{
"id": "101",
"uri": "s3://example_bucket/import",
"status": "InProgress",
"created_at": "2024-08-19T20:49:00.754Z",
"finished_at": "2024-08-19T20:49:00.754Z",
"percent_complete": 42.2,
"records_imported": 1000000
}
```
If the import fails, the response contains an `error` field with the reason for the failure. See the [Troubleshooting](#troubleshooting) section for more information.
```json Response theme={null}
{
"id": "102",
"uri": "s3://example_bucket/import",
"status": "Failed",
"percent_complete": 0.0,
"records_imported": 0,
"created_at": "2025-08-21T11:29:47.886797+00:00",
"error": "User error: The namespace \"namespace1\" already exists. Imports are only allowed into nonexistent namespaces.",
"finished_at": "2025-08-21T11:30:05.506423+00:00"
}
```
## Manage imports
### List imports
Use the [`list_imports`](/reference/api/latest/data-plane/list_imports) operation to list all of the recent and ongoing imports. By default, the operation returns up to 100 imports per page. If the `limit` parameter is passed, the operation returns up to that number of imports per page instead. For example, if `limit=3`, up to 3 imports are returned per page. Whenever there are additional imports to return, the response includes a `pagination_token` for fetching the next page of imports.
When using the Python SDK, `list_import` paginates automatically.
```python Python theme={null}
from pinecone import Pinecone, ImportErrorMode
pc = Pinecone(api_key="YOUR_API_KEY")
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
index = pc.Index(host="INDEX_HOST")
# List using a generator that handles pagination
for i in index.list_imports():
print(f"id: {i.id} status: {i.status}")
# List using a generator that fetches all results at once
operations = list(index.list_imports())
print(operations)
```
```json Response theme={null}
{
"data": [
{
"id": "1",
"uri": "s3://BUCKET_NAME/PATH/TO/DIR",
"status": "Pending",
"started_at": "2024-08-19T20:49:00.754Z",
"finished_at": "2024-08-19T20:49:00.754Z",
"percent_complete": 42.2,
"records_imported": 1000000
}
],
"pagination": {
"next": "Tm90aGluZyB0byBzZWUgaGVyZQo="
}
}
```
You can view the list of imports for an index in the [Pinecone console](https://app.pinecone.io/organizations/-/projects/-/indexes/). Select the index and navigate to the **Imports** tab.
When using the Node.js SDK, Java SDK, Go SDK, or REST API to list recent and ongoing imports, you must manually fetch each page of results. To view the next page of results, include the `paginationToken` provided in the response.
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' });
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
const index = pc.index("INDEX_NAME", "INDEX_HOST")
const results = await index.listImports({ limit: 10, paginationToken: 'Tm90aGluZyB0byBzZWUgaGVyZQo' });
console.log(results);
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import io.pinecone.clients.AsyncIndex;
import org.openapitools.db_data.client.ApiException;
import org.openapitools.db_data.client.model.ListImportsResponse;
public class ListImports {
public static void main(String[] args) throws ApiException {
// Initialize a Pinecone client with your API key
Pinecone pinecone = new Pinecone.Builder("YOUR_API_KEY").build();
// Get async imports connection object
AsyncIndex asyncIndex = pinecone.getAsyncIndexConnection("docs-example");
// List imports
ListImportsResponse response = asyncIndex.listImports(10, "Tm90aGluZyB0byBzZWUgaGVyZQo");
System.out.println(response);
}
}
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
idxConnection, err := pc.Index(pinecone.NewIndexConnParams{Host: "INDEX_HOST"})
if err != nil {
log.Fatalf("Failed to create IndexConnection for Host: %v", err)
}
limit := int32(10)
firstImportPage, err := idxConnection.ListImports(ctx, &limit, nil)
if err != nil {
log.Fatalf("Failed to list imports: %v", err)
}
fmt.Printf("First page of imports: %+v", firstImportPage.Imports)
paginationToken := firstImportPage.NextPaginationToken
nextImportPage, err := idxConnection.ListImports(ctx, &limit, paginationToken)
if err != nil {
log.Fatalf("Failed to list imports: %v", err)
}
fmt.Printf("Second page of imports: %+v", nextImportPage.Imports)
}
```
```bash curl theme={null}
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
curl -X GET "https://$INDEX_HOST/bulk/imports?paginationToken==Tm90aGluZyB0byBzZWUgaGVyZQo" \
-H 'Api-Key: $YOUR_API_KEY' \
-H 'X-Pinecone-Api-Version: 2025-10'
```
### Cancel an import
The [`cancel_import`](/reference/api/latest/data-plane/cancel_import) operation cancels an import if it is not yet finished. It has no effect if the import is already complete.
```python Python theme={null}
from pinecone import Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
index = pc.Index(host="INDEX_HOST")
index.cancel_import(id="101")
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' });
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
const index = pc.index("INDEX_NAME", "INDEX_HOST")
await index.cancelImport(id='101');
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import io.pinecone.clients.AsyncIndex;
import org.openapitools.db_data.client.ApiException;
public class CancelImport {
public static void main(String[] args) throws ApiException {
// Initialize a Pinecone client with your API key
Pinecone pinecone = new Pinecone.Builder("YOUR_API_KEY").build();
// Get async imports connection object
AsyncIndex asyncIndex = pinecone.getAsyncIndexConnection("docs-example");
// Cancel import
asyncIndex.cancelImport("2");
}
}
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
idxConnection, err := pc.Index(pinecone.NewIndexConnParams{Host: "INDEX_HOST"})
if err != nil {
log.Fatalf("Failed to create IndexConnection for Host: %v", err)
}
importID := "101"
err = idxConnection.CancelImport(ctx, importID)
if err != nil {
log.Fatalf("Failed to cancel import: %s", importID)
}
importDesc, err := idxConnection.DescribeImport(ctx, importID)
if err != nil {
log.Fatalf("Failed to describe import: %s - %v", importID, err)
}
}
```
```bash curl theme={null}
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
curl -X DELETE "https://{INDEX_HOST}/bulk/imports/101" \
-H 'Api-Key: $YOUR_API_KEY' \
-H "X-Pinecone-Api-Version: 2025-10"
```
```json Response theme={null}
{}
```
You can cancel your import using the [Pinecone console](https://app.pinecone.io/organizations/-/projects/-/import). To cancel an ongoing import, select the index you are importing into and navigate to the **Imports** tab. Then, click the **ellipsis (...) menu > Cancel**.
## Import limits
If your import exceeds these limits, you'll get an error specifying the limit exceeded. See [Troubleshooting](/guides/index-data/import-data#troubleshooting) for details.
| Metric | Limit |
| :-------------------------------------------- | :-------- |
| Max namespaces per import | 10,000 |
| Max total input data size (on-demand indexes) | 1 TB |
| Max total input data size (DRN indexes) | Unlimited |
| Max files per import | 100,000 |
| Max size per file | 10 GB |
The total input data size limit does not apply to indexes with [dedicated read nodes](/guides/index-data/dedicated-read-nodes).
Bulk import supports indexes without a schema definition (Parquet files) and indexes with document schemas ([JSONL files](/guides/search/full-text-search#bulk-import)). Semantic-text (auto-embedded) fields are not yet supported in document schemas.
Also:
* You cannot import data from an AWS S3 bucket into a Pinecone index hosted on GCP or Azure.
* You cannot import data from S3 Express One Zone storage.
* You cannot import data into an existing namespace.
* When importing data into the `__default__` namespace of an index, the default namespace must be empty.
* Each import takes at least 10 minutes to complete.
* When importing into an [index with integrated embedding](/guides/index-data/indexing-overview#vector-embedding), records must contain vectors, not text. To add records with text, you must use [upsert](/guides/index-data/upsert-data).
## Troubleshooting
When an import fails, you'll see an error message with the reason for the failure in the [Pinecone console](https://app.pinecone.io/organizations/-/projects/-/import) or in the response to the [describe an import](/reference/api/latest/data-plane/describe_import) operation.
You cannot import data into an existing namespace. If your import directory structure contains a folder with the name of an existing namespace in your index, the import will fail with the following error:
```
User error: The namespace "example-namespace" already exists. Imports are only allowed into nonexistent namespaces.
```
To fix this, rename the folder to use a namespace name that does not yet exist.
In object storage, your directory structure must be as follows:
```
example_bucket/
--/imports/
----/example_namespace1/
------0.parquet
------1.parquet
------2.parquet
------3.parquet
----/example_namespace2/
------4.parquet
------5.parquet
------6.parquet
------7.parquet
```
If a Parquet file is not nested under a namespace subdirectory, the import will fail with the following error:
```
User error: \"test-import/0.parquet\": No namespace detected. Each file should be nested under a subdirectory of the URI prefix. This indicates which namespace it should be imported into.
```
To fix this, move the Parquet file to a namespace subdirectory.
Each namespace subdirectory must contain Parquet files with data to import. If a namespace subdirectory does not include Parquet files, the import will fail with the following error:
```
User error: No Parquet files found under \"gs://example_bucket/imports\". Files must be stored with the specified bucket prefix.
```
To fix this, add Parquet files to the namespace subdirectory.
In your [start import](/reference/api/latest/data-plane/start_import) request, the import `uri` must specify only the bucket and import directory containing the namespaces and Parquet files you want to import. If the `uri` also contains a namespaces directory or a Parquet filename, the import will fail with the following error:
```
User error: \"test-import/0.parquet\": It looks like you specified a complete path to a parquet file as the URI prefix to import from. Note that the URI prefix should give an ancestor directory with subdirectories to specify each namespace to import into. See https://docs.pinecone.io/guides/data/understanding-imports#directory-structure.
```
To fix this, remove the namespaces directory or Parquet filename from the `uri`.
When a Parquet file is not formatted correctly, the import will fail with a message like one of the following:
```shell File schema errors theme={null}
Missing required column \"{0}\"
Unsupported column \"{0}\"
```
```shell File corruption errors theme={null}
Parquet footer could not be parsed. Are you sure this is valid parquet?
```
```shell Type errors theme={null}
The expected data type for column \"{column}\" is \"{expected}\", but got \"{given}\"
The expected data type for metadata is a JSON encoded string in UTF-8 format, but got \"{given}\"
```
These errors are returned for both `continue` and `abort` error modes.
To fix these errors, check the specific error message and follow the instructions in the [Prepare your data](#prepare-your-data) section.
When the `error_mode` is `abort` and a file contains invalid records, the import will stop processing on the first invalid record and return an error message identifying the file name and row:
```
User error: error reading record (file \"/0.parquet\", row 0):
```
This will be followed by an error message identifying the specific issue. For example:
```shell Missing values theme={null}
missing required values in column \"{column}\"
```
```shell Invalid metadata theme={null}
Failed to parse metadata: {msg}
```
```shell Invalid vectors theme={null}
Upserting dense vectors is not supported for indexes that store only sparse vectors
```
When the `error_mode` is `continue`, the import will skip individual invalid records. However, if all records are invalid and skipped (for example, the vector type in the file does not match the vector type of the index), the import will fail with a general message:
```
User error: No vectors added, all rows were skipped for namespace: example-namespace
```
To fix these errors, check the specific error message and follow the instructions in the [Prepare your data](#prepare-your-data) section.
When your import contains duplicate vectors (records with identical vector values), the duplicates are marked as skipped and not imported. Only one occurrence of each unique vector is added to the index.
This applies to both `continue` and `abort` error modes:
* With `abort`: The import fails when it encounters a duplicate vector within the import.
* With `continue`: The import proceeds, skipping duplicate records silently.
**Example scenario:**
If your Parquet file contains:
```parquet theme={null}
id | values
---|---------
1 | [0.1, 0.2, 0.3]
2 | [0.1, 0.2, 0.3] ← Duplicate of record 1, will be skipped
3 | [0.4, 0.5, 0.6]
```
Only records 1 and 3 will be imported.
To prevent this from happening, deduplicate your source data before creating Parquet files by removing records with identical vector values.
On-demand indexes have a maximum total input data size of 1 TB per import. If your import exceeds this limit, it will fail with the following error:
```
Import ({size} GB) exceeds the maximum input data size of 1000 GB for on-demand. Consider using Dedicated Read Nodes (DRN) for larger index sizes, or contact support for your use-case.
```
To fix this, either reduce the total size of your import to under 1 TB, use an index with [dedicated read nodes](/guides/index-data/dedicated-read-nodes) (which have no total data size limit for imports), or [contact support](https://app.pinecone.io/organizations/-/settings/support/ticket).
## See also
* [Integrate with Amazon S3](/guides/operations/integrations/integrate-with-amazon-s3)
* [Integrate with Google Cloud Storage](/guides/operations/integrations/integrate-with-google-cloud-storage)
* [Integrate with Azure Blob Storage](/guides/operations/integrations/integrate-with-azure-blob-storage)
* [Pinecone's pricing](https://www.pinecone.io/pricing/)
# Indexing overview
Source: https://docs.pinecone.io/guides/index-data/indexing-overview
Learn how indexing works in Pinecone: serverless indexes, document schemas, namespaces, integrated embedding, and metadata filtering.
## Indexes
In Pinecone, you store data in indexes. A serverless index holds your data as [documents](/guides/get-started/concepts#document) or [records](/guides/get-started/concepts#record), depending on how the index was created: an index created with a document schema holds documents, while an index created with a dense or sparse vector type holds records. A single index with a document schema can mix multiple ranking field types: a `dense_vector` field for [semantic search](/guides/search/semantic-search), a `sparse_vector` field for [sparse-vector retrieval](/guides/search/lexical-search), and one or more `string` fields with `full_text_search` enabled for [full-text search](/guides/search/full-text-search) with BM25 and Lucene queries. Any other fields you upsert are stored as metadata, automatically indexed for filtering — no schema declaration required.
One index per use case is the typical pattern. Because a document can combine vectors, text, and metadata in the same record, a single index often covers what previously required two — pick the ranking signal per query with `score_by`.
### Full-text search
Full-text search is **BM25 token matching with Lucene query syntax** over text fields in your schema — `string` fields you've declared with `full_text_search` enabled. No model required — Pinecone handles tokenization, IDF, and length normalization at index time and BM25 scoring at query time.
When you search, you rank results via `score_by`: `text` (BM25), `query_string` (Lucene), `dense_vector`, or `sparse_vector`. All scoring methods can be combined with metadata filters, including the text match operators (`$match_phrase`, `$match_all`, `$match_any`) for phrase and token matching. For example:
```json theme={null}
{
"score_by": [{ "type": "text", "field": "body", "query": "machine learning" }],
"top_k": 10
}
```
Reach for full-text search when relevance comes down to specific tokens appearing in both the query and the data: SKUs, error messages, code, named entities. For semantic similarity over natural-language queries, see [Indexes with dense vectors](#indexes-with-dense-vectors); for retrieval with a learned sparse encoder, see [Indexes with sparse vectors](#indexes-with-sparse-vectors).
Learn more:
* [Full-text search guide](/guides/search/full-text-search)
* [Schema definition](/guides/search/full-text-search#schema-definition)
* [Upsert documents](/guides/search/full-text-search#upsert-documents)
### Indexes with dense vectors
A dense vector encodes the meaning of text, images, or other data as a fixed-length list of numbers. Items with similar meaning sit close to each other in vector space, and a query returns the records closest to the query vector. This is **semantic search** (also called nearest neighbor search, similarity search, or vector search).
For the underlying concept, see [Dense vector](/guides/get-started/concepts#dense-vector).
Learn more:
* [Create an index for dense vectors](/guides/index-data/create-an-index#create-an-index-for-dense-vectors)
* [Upsert dense vectors](/guides/index-data/upsert-data#upsert-dense-vectors)
* [Semantic search](/guides/search/semantic-search)
### Indexes with sparse vectors
A sparse vector represents tokens (or token-like features) and their weights, with the vast majority of dimensions zero. A query returns records that share the most weighted tokens with the query vector — **sparse-vector lexical search**.
Sparse vectors come from a sparse embedding model. Pinecone hosts [`pinecone-sparse-english-v0`](/models/pinecone-sparse-english-v0); you can also bring your own. For the underlying concept and the distinction from full-text search, see [Index with sparse vectors](/guides/get-started/concepts#index-with-sparse-vectors).
Learn more:
* [Create an index for sparse vectors](/guides/index-data/create-an-index#create-an-index-for-sparse-vectors)
* [Upsert sparse vectors](/guides/index-data/upsert-data#upsert-sparse-vectors)
* [Lexical search](/guides/search/lexical-search)
#### Limitations
Indexes of sparse vectors have the following limitations:
* Max non-zero values per sparse vector: 1000
* Max upserts per second per index of sparse vectors: 10
* Max queries per second per index of sparse vectors: 100
* Max `top_k` value per query: 1000
You may get fewer than `top_k` results if `top_k` is larger than the number of sparse vectors in your index that match your query. That is, any vectors where the dotproduct score is `0` will be discarded.
* Max query results size: 4MB
Semantic search can miss exact keyword matches, while lexical search can miss semantically related results. To get the best of both, use [hybrid search](/guides/search/hybrid-search) — combine a lexical signal (BM25 or sparse) with a dense signal at query time, often with reranking.
## Namespaces
Within an index, records are partitioned into namespaces, and all [upserts](/guides/index-data/upsert-data), [queries](/guides/search/search-overview), and other data read and write operations always target one namespace. This has two main benefits:
* **Multitenancy:** When you need to isolate data between customers, you can use one namespace per customer and target each customer's writes and queries to their dedicated namespace. See [Implement multitenancy](/guides/index-data/implement-multitenancy) for end-to-end guidance.
* **Faster queries:** When you divide records into namespaces in a logical way, you speed up queries by ensuring only relevant records are scanned. The same applies to fetching records, listing record IDs, and other data operations.
Namespaces are created automatically during [upsert](/guides/index-data/upsert-data). If a namespace doesn't exist, it is created implicitly.
[Namespaces per serverless index](/reference/api/database-limits#namespaces-per-serverless-index) vary by plan. On the Standard and Enterprise plans, Pinecone can accommodate million-scale namespaces and beyond for specific use cases. If your application requires more than 100,000 namespaces, [contact Support](https://app.pinecone.io/organizations/-/settings/support/ticket).
## Vector embedding
[Dense vectors](/guides/get-started/concepts#dense-vector) and [sparse vectors](/guides/get-started/concepts#sparse-vector) are the basic units of data in Pinecone and what Pinecone was specially designed to store and work with. Dense vectors represents the semantics of data such as text, images, and audio recordings, while sparse vectors represent documents or queries in a way that captures keyword information.
To transform data into vector format, you use an embedding model. You can either use Pinecone's integrated embedding models to convert your source data to vectors automatically, or you can use an external embedding model and bring your own vectors to Pinecone.
### Integrated embedding
1. [Create an index](/guides/index-data/create-an-index) that is integrated with one of Pinecone's [hosted embedding models](/guides/index-data/create-an-index#embedding-models).
2. [Upsert](/guides/index-data/upsert-data) your source text. Pinecone uses the integrated model to convert the text to vectors automatically.
3. [Search](/guides/search/search-overview) with a query text. Again, Pinecone uses the integrated model to convert the text to a vector automatically.
Indexes with integrated embedding do not support [updating](/guides/manage-data/update-data) or [importing](/guides/index-data/import-data) with text.
### Bring your own vectors
1. Use an embedding model to convert your text to vectors. The model can be [hosted by Pinecone](/reference/api/latest/inference/generate-embeddings) or an external provider.
2. [Create an index](/guides/index-data/create-an-index) that matches the characteristics of the model.
3. [Upsert](/guides/index-data/upsert-data) your vectors directly.
4. Use the same external embedding model to convert a query to a vector.
5. [Search](/guides/search/search-overview) with your query vector directly.
## Data ingestion
To control costs when ingesting large datasets (10,000,000+ records), use [import](/guides/index-data/import-data) instead of upsert.
There are two ways to ingest data into an index:
* [Importing from object storage](/guides/index-data/import-data) is the most efficient and cost-effective way to load large numbers of records into an index. You store your data as Parquet files in object storage, integrate your object storage with Pinecone, and then start an asynchronous, long-running operation that imports and indexes your records.
* [Upserting](/guides/index-data/upsert-data) is intended for ongoing writes to an index. [Batch upserting](/guides/index-data/upsert-data#upsert-in-batches) can improve throughput performance and is a good option for larger numbers of records (up to 1000 per batch) if you cannot work around import's current limitations.
## Metadata
Every [record](/guides/get-started/concepts#record) in an index must contain an ID and a vector. In addition, you can include metadata key-value pairs to store additional information or context. When you query the index, you can then include a [metadata filter](/guides/search/filter-by-metadata) to limit the search to records matching a filter expression. Searches without metadata filters do not consider metadata and search the entire namespace.
### Metadata format
* Metadata fields must be key-value pairs in a flat JSON object. Nested JSON objects are not supported.
* Keys must be strings and must not start with a `$`.
* Values must be one of the following data types:
* String
* Integer (converted to a 64-bit floating point by Pinecone)
* Floating point
* Boolean (`true`, `false`)
* List of strings
* Null metadata values aren't supported. Instead of setting a key to `null`, remove the key from the metadata payload.
**Examples**
```json Valid metadata theme={null}
{
"document_id": "document1",
"document_title": "Introduction to Vector Databases",
"chunk_number": 1,
"chunk_text": "First chunk of the document content...",
"is_public": true,
"tags": ["beginner", "database", "vector-db"],
"scores": ["85", "92"]
}
```
```json Invalid metadata theme={null}
{
"document": { // Nested JSON objects are not supported
"document_id": "document1",
"document_title": "Introduction to Vector Databases",
},
"$chunk_number": 1, // Keys must not start with a `$`
"chunk_text": null, // Null values are not supported
"is_public": true,
"tags": ["beginner", "database", "vector-db"],
"scores": [85, 92] // Lists of non-strings are not supported
}
```
### Metadata size
Pinecone supports 40KB of metadata per record.
### Metadata filter expressions
Pinecone's filtering language supports the following operators:
| Operator | Function | Supported types |
| :-------- | :------------------------------------------------------------------------------------------------------------------------- | :---------------------- |
| `$eq` | Matches with metadata values that are equal to a specified value. Example: `{"genre": {"$eq": "documentary"}}` | Number, string, boolean |
| `$ne` | Matches with metadata values that are not equal to a specified value. Example: `{"genre": {"$ne": "drama"}}` | Number, string, boolean |
| `$gt` | Matches with metadata values that are greater than a specified value. Example: `{"year": {"$gt": 2019}}` | Number |
| `$gte` | Matches with metadata values that are greater than or equal to a specified value. Example:`{"year": {"$gte": 2020}}` | Number |
| `$lt` | Matches with metadata values that are less than a specified value. Example: `{"year": {"$lt": 2020}}` | Number |
| `$lte` | Matches with metadata values that are less than or equal to a specified value. Example: `{"year": {"$lte": 2020}}` | Number |
| `$in` | Matches with metadata values that are in a specified array. Example: `{"genre": {"$in": ["comedy", "documentary"]}}` | String, number |
| `$nin` | Matches with metadata values that are not in a specified array. Example: `{"genre": {"$nin": ["comedy", "documentary"]}}` | String, number |
| `$exists` | Matches with the specified metadata field. Example: `{"genre": {"$exists": true}}` | Number, string, boolean |
| `$and` | Joins query clauses with a logical `AND`. Example: `{"$and": [{"genre": {"$eq": "drama"}}, {"year": {"$gte": 2020}}]}` | - |
| `$or` | Joins query clauses with a logical `OR`. Example: `{"$or": [{"genre": {"$eq": "drama"}}, {"year": {"$gte": 2020}}]}` | - |
Only `$and` and `$or` are allowed at the top level of the query expression.
Each `$in` or `$nin` operator accepts a maximum of 10,000 values. Exceeding this limit will cause the request to fail. For more information, see [Metadata filter limits](/reference/api/database-limits#metadata-filter-limits).
For example, the following has a `"genre"` metadata field with a list of strings:
```JSON JSON theme={null}
{ "genre": ["comedy", "documentary"] }
```
This means `"genre"` takes on both values, and requests with the following filters will match:
```JSON JSON theme={null}
{"genre":"comedy"}
{"genre": {"$in":["documentary","action"]}}
{"$and": [{"genre": "comedy"}, {"genre":"documentary"}]}
```
However, requests with the following filter will **not** match:
```JSON JSON theme={null}
{ "$and": [{ "genre": "comedy" }, { "genre": "drama" }] }
```
Additionally, requests with the following filters will **not** match because they are invalid. They will result in a compilation error:
```json JSON theme={null}
# INVALID QUERY:
{"genre": ["comedy", "documentary"]}
```
```json JSON theme={null}
# INVALID QUERY:
{"genre": {"$eq": ["comedy", "documentary"]}}
```
# Upsert records
Source: https://docs.pinecone.io/guides/index-data/upsert-data
Upsert dense, sparse, and text records into Pinecone indexes, batch upserts for higher throughput, and partition data with namespaces.
This page shows you how to upsert records into a namespace in an index. [Namespaces](/guides/index-data/indexing-overview#namespaces) let you partition records within an index and are essential for [implementing multitenancy](/guides/index-data/implement-multitenancy) when you need to isolate the data of each customer/user.
If a record ID already exists, upserting overwrites the entire record. To change only part of a record, [update ](/guides/manage-data/update-data) the record.
Upserts consume [write units (WUs)](/guides/manage-cost/understanding-cost#write-units). See [Understanding cost](/guides/manage-cost/understanding-cost#upsert) for how upsert cost is calculated.
To control costs when ingesting large datasets (10,000,000+ records), use [import](/guides/index-data/import-data) instead of upsert.
## Upsert dense vectors
Upserting text is supported only for [indexes with integrated embedding](/guides/index-data/indexing-overview#integrated-embedding).
To upsert source text into an [index of dense vectors with integrated embedding](/guides/index-data/create-an-index#create-an-index-for-dense-vectors), use the [`upsert_records`](/reference/api/latest/data-plane/upsert_records) operation. Pinecone converts the text to dense vectors automatically using the hosted dense embedding model associated with the index.
* Specify the [`namespace`](/guides/index-data/indexing-overview#namespaces) to upsert into. If the namespace doesn't exist, it is created. To use the default namespace, set the namespace to `"__default__"`.
* Format your input data as records, each with the following:
* An `_id` field with a unique record identifier for the index namespace. `id` can be used as an alias for `_id`.
* A field with the source text to convert to a vector. This field must match the `field_map` specified in the index.
* Additional fields are stored as record [metadata](/guides/index-data/indexing-overview#metadata) and can be returned in search results or used to [filter search results](/guides/search/filter-by-metadata).
For example, the following code converts the sentences in the `chunk_text` fields to dense vectors and then upserts them into `example-namespace` in an example index. The additional `category` field is stored as metadata.
```python Python theme={null}
from pinecone import Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
index = pc.Index(host="INDEX_HOST")
# Upsert records into a namespace
# `chunk_text` fields are converted to dense vectors
# `category` fields are stored as metadata
index.upsert_records(
"example-namespace",
[
{
"_id": "rec1",
"chunk_text": "Apples are a great source of dietary fiber, which supports digestion and helps maintain a healthy gut.",
"category": "digestive system",
},
{
"_id": "rec2",
"chunk_text": "Apples originated in Central Asia and have been cultivated for thousands of years, with over 7,500 varieties available today.",
"category": "cultivation",
},
{
"_id": "rec3",
"chunk_text": "Rich in vitamin C and other antioxidants, apples contribute to immune health and may reduce the risk of chronic diseases.",
"category": "immune system",
},
{
"_id": "rec4",
"chunk_text": "The high fiber content in apples can also help regulate blood sugar levels, making them a favorable snack for people with diabetes.",
"category": "endocrine system",
},
]
)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({ apiKey: "YOUR_API_KEY" })
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
const namespace = pc.index("INDEX_NAME", "INDEX_HOST").namespace("example-namespace");
// Upsert records into a namespace
// `chunk_text` fields are converted to dense vectors
// `category` is stored as metadata
await namespace.upsertRecords([
{
"_id": "rec1",
"chunk_text": "Apples are a great source of dietary fiber, which supports digestion and helps maintain a healthy gut.",
"category": "digestive system",
},
{
"_id": "rec2",
"chunk_text": "Apples originated in Central Asia and have been cultivated for thousands of years, with over 7,500 varieties available today.",
"category": "cultivation",
},
{
"_id": "rec3",
"chunk_text": "Rich in vitamin C and other antioxidants, apples contribute to immune health and may reduce the risk of chronic diseases.",
"category": "immune system",
},
{
"_id": "rec4",
"chunk_text": "The high fiber content in apples can also help regulate blood sugar levels, making them a favorable snack for people with diabetes.",
"category": "endocrine system",
}
]);
```
```java Java theme={null}
import io.pinecone.clients.Index;
import io.pinecone.configs.PineconeConfig;
import io.pinecone.configs.PineconeConnection;
import org.openapitools.db_data.client.ApiException;
import java.util.*;
public class UpsertText {
public static void main(String[] args) throws ApiException {
PineconeConfig config = new PineconeConfig("YOUR_API_KEY");
config.setHost("INDEX_HOST");
PineconeConnection connection = new PineconeConnection(config);
Index index = new Index(config, connection, "integrated-dense-java");
ArrayList
To upsert dense vectors into an [index of dense vectors](/guides/index-data/create-an-index#create-an-index-for-dense-vectors), use the [`upsert`](/reference/api/latest/data-plane/upsert) operation as follows:
* Specify the [`namespace`](/guides/index-data/indexing-overview#namespaces) to upsert into. If the namespace doesn't exist, it is created. To use the default namespace, set the namespace to `"__default__"`.
* Format your input data as records, each with the following:
* An `id` field with a unique record identifier for the index namespace.
* A `values` field with the dense vector values.
* Optionally, a `metadata` field with [key-value pairs](/guides/index-data/indexing-overview#metadata) to store additional information or context. When you query the index, you can use metadata to [filter search results](/guides/search/filter-by-metadata).
```Python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
index = pc.Index(host="INDEX_HOST")
index.upsert(
vectors=[
{
"id": "A",
"values": [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1],
"metadata": {"genre": "comedy", "year": 2020}
},
{
"id": "B",
"values": [0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2],
"metadata": {"genre": "documentary", "year": 2019}
},
{
"id": "C",
"values": [0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3],
"metadata": {"genre": "comedy", "year": 2019}
},
{
"id": "D",
"values": [0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4],
"metadata": {"genre": "drama"}
}
],
namespace="example-namespace"
)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({ apiKey: "YOUR_API_KEY" })
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
const index = pc.index("INDEX_NAME", "INDEX_HOST")
const records = [
{
id: 'A',
values: [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1],
metadata: { genre: "comedy", year: 2020 },
},
{
id: 'B',
values: [0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2],
metadata: { genre: "documentary", year: 2019 },
},
{
id: 'C',
values: [0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3],
metadata: { genre: "comedy", year: 2019 },
},
{
id: 'D',
values: [0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4],
metadata: { genre: "drama" },
}
]
await index.namespace('example-namespace').upsert({ records: records });
```
```java Java theme={null}
import com.google.protobuf.Struct;
import com.google.protobuf.Value;
import io.pinecone.clients.Index;
import io.pinecone.configs.PineconeConfig;
import io.pinecone.configs.PineconeConnection;
import java.util.Arrays;
import java.util.List;
public class UpsertExample {
public static void main(String[] args) {
PineconeConfig config = new PineconeConfig("YOUR_API_KEY");
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
config.setHost("INDEX_HOST");
PineconeConnection connection = new PineconeConnection(config);
Index index = new Index(connection, "INDEX_NAME");
List values1 = Arrays.asList(0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f);
List values2 = Arrays.asList(0.2f, 0.2f, 0.2f, 0.2f, 0.2f, 0.2f, 0.2f, 0.2f);
List values3 = Arrays.asList(0.3f, 0.3f, 0.3f, 0.3f, 0.3f, 0.3f, 0.3f, 0.3f);
List values4 = Arrays.asList(0.4f, 0.4f, 0.4f, 0.4f, 0.4f, 0.4f, 0.4f, 0.4f);
Struct metaData1 = Struct.newBuilder()
.putFields("genre", Value.newBuilder().setStringValue("comedy").build())
.putFields("year", Value.newBuilder().setNumberValue(2020).build())
.build();
Struct metaData2 = Struct.newBuilder()
.putFields("genre", Value.newBuilder().setStringValue("documentary").build())
.putFields("year", Value.newBuilder().setNumberValue(2019).build())
.build();
Struct metaData3 = Struct.newBuilder()
.putFields("genre", Value.newBuilder().setStringValue("comedy").build())
.putFields("year", Value.newBuilder().setNumberValue(2019).build())
.build();
Struct metaData4 = Struct.newBuilder()
.putFields("genre", Value.newBuilder().setStringValue("drama").build())
.build();
index.upsert("A", values1, null, null, metaData1, 'example-namespace');
index.upsert("B", values2, null, null, metaData2, 'example-namespace');
index.upsert("C", values3, null, null, metaData3, 'example-namespace');
index.upsert("D", values4, null, null, metaData4, 'example-namespace');
}
}
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
"google.golang.org/protobuf/types/known/structpb"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
idxConnection, err := pc.Index(pinecone.NewIndexConnParams{Host: "INDEX_HOST", Namespace: "example-namespace"})
if err != nil {
log.Fatalf("Failed to create IndexConnection for Host: %v", err)
}
metadataMap1 := map[string]interface{}{
"genre": "comedy",
"year": 2020,
}
metadata1, err := structpb.NewStruct(metadataMap1)
if err != nil {
log.Fatalf("Failed to create metadata map: %v", err)
}
metadataMap2 := map[string]interface{}{
"genre": "documentary",
"year": 2019,
}
metadata2, err := structpb.NewStruct(metadataMap2)
if err != nil {
log.Fatalf("Failed to create metadata map: %v", err)
}
metadataMap3 := map[string]interface{}{
"genre": "comedy",
"year": 2019,
}
metadata3, err := structpb.NewStruct(metadataMap3)
if err != nil {
log.Fatalf("Failed to create metadata map: %v", err)
}
metadataMap4 := map[string]interface{}{
"genre": "drama",
}
metadata4, err := structpb.NewStruct(metadataMap4)
if err != nil {
log.Fatalf("Failed to create metadata map: %v", err)
}
vectors := []*pinecone.Vector{
{
Id: "A",
Values: []float32{0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1},
Metadata: metadata1,
},
{
Id: "B",
Values: []float32{0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2},
Metadata: metadata2,
},
{
Id: "C",
Values: []float32{0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3},
Metadata: metadata3,
},
{
Id: "D",
Values: []float32{0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4},
Metadata: metadata4,
},
}
count, err := idxConnection.UpsertVectors(ctx, vectors)
if err != nil {
log.Fatalf("Failed to upsert vectors: %v", err)
} else {
fmt.Printf("Successfully upserted %d vector(s)!\n", count)
}
}
```
```bash curl theme={null}
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
curl "https://$INDEX_HOST/vectors/upsert" \
-H "Api-Key: $PINECONE_API_KEY" \
-H 'Content-Type: application/json' \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"vectors": [
{
"id": "A",
"values": [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1],
"metadata": {"genre": "comedy", "year": 2020}
},
{
"id": "B",
"values": [0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2],
"metadata": {"genre": "documentary", "year": 2019}
},
{
"id": "C",
"values": [0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3],
"metadata": {"genre": "comedy", "year": 2019}
},
{
"id": "D",
"values": [0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4],
"metadata": {"genre": "drama"}
}
],
"namespace": "example-namespace"
}'
```
## Upsert sparse vectors
Sparse-vector upsert is the right choice when your data is encoded by a learned sparse model (for example, [`pinecone-sparse-english-v0`](/models/pinecone-sparse-english-v0)) or when your application owns the sparse-vector representation directly. For BM25-style keyword search over raw text with no model to manage, see [Upsert documents](#upsert-documents).
Upserting text is supported only for [indexes with integrated embedding](/guides/index-data/indexing-overview#integrated-embedding).
To upsert source text into an [index of sparse vectors with integrated embedding](/guides/index-data/create-an-index#create-an-index-for-sparse-vectors), use the [`upsert_records`](/reference/api/latest/data-plane/upsert_records) operation. Pinecone converts the text to sparse vectors automatically using the hosted sparse embedding model associated with the index.
* Specify the [`namespace`](/guides/index-data/indexing-overview#namespaces) to upsert into. If the namespace doesn't exist, it is created. To use the default namespace, set the namespace to `"__default__"`.
* Format your input data as records, each with the following:
* An `_id` field with a unique record identifier for the index namespace. `id` can be used as an alias for `_id`.
* A field with the source text to convert to a vector. This field must match the `field_map` specified in the index.
* Additional fields are stored as record [metadata](/guides/index-data/indexing-overview#metadata) and can be returned in search results or used to [filter search results](/guides/search/filter-by-metadata).
For example, the following code converts the sentences in the `chunk_text` fields to sparse vectors and then upserts them into `example-namespace` in an example index. The additional `category` and `quarter` fields are stored as metadata.
```python Python theme={null}
from pinecone import Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
index = pc.Index(host="INDEX_HOST")
# Upsert records into a namespace
# `chunk_text` fields are converted to sparse vectors
# `category` and `quarter` fields are stored as metadata
index.upsert_records(
"example-namespace",
[
{
"_id": "vec1",
"chunk_text": "AAPL reported a year-over-year revenue increase, expecting stronger Q3 demand for its flagship phones.",
"category": "technology",
"quarter": "Q3"
},
{
"_id": "vec2",
"chunk_text": "Analysts suggest that AAPL'\''s upcoming Q4 product launch event might solidify its position in the premium smartphone market.",
"category": "technology",
"quarter": "Q4"
},
{
"_id": "vec3",
"chunk_text": "AAPL'\''s strategic Q3 partnerships with semiconductor suppliers could mitigate component risks and stabilize iPhone production.",
"category": "technology",
"quarter": "Q3"
},
{
"_id": "vec4",
"chunk_text": "AAPL may consider healthcare integrations in Q4 to compete with tech rivals entering the consumer wellness space.",
"category": "technology",
"quarter": "Q4"
}
]
)
time.sleep(10) # Wait for the upserted vectors to be indexed
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({ apiKey: "YOUR_API_KEY" })
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
const namespace = pc.index("INDEX_NAME", "INDEX_HOST").namespace("example-namespace");
// Upsert records into a namespace
// `chunk_text` fields are converted to sparse vectors
// `category` and `quarter` fields are stored as metadata
await namespace.upsertRecords([
{
"_id": "vec1",
"chunk_text": "AAPL reported a year-over-year revenue increase, expecting stronger Q3 demand for its flagship phones.",
"category": "technology",
"quarter": "Q3"
},
{
"_id": "vec2",
"chunk_text": "Analysts suggest that AAPL'\''s upcoming Q4 product launch event might solidify its position in the premium smartphone market.",
"category": "technology",
"quarter": "Q4"
},
{
"_id": "vec3",
"chunk_text": "AAPL'\''s strategic Q3 partnerships with semiconductor suppliers could mitigate component risks and stabilize iPhone production.",
"category": "technology",
"quarter": "Q3"
},
{
"_id": "vec4",
"chunk_text": "AAPL may consider healthcare integrations in Q4 to compete with tech rivals entering the consumer wellness space.",
"category": "technology",
"quarter": "Q4"
}
]);
```
```java Java theme={null}
import io.pinecone.clients.Index;
import io.pinecone.configs.PineconeConfig;
import io.pinecone.configs.PineconeConnection;
import org.openapitools.db_data.client.ApiException;
import java.util.*;
public class UpsertText {
public static void main(String[] args) throws ApiException {
PineconeConfig config = new PineconeConfig("YOUR_API_KEY");
config.setHost("INDEX_HOST");
PineconeConnection connection = new PineconeConnection(config);
Index index = new Index(config, connection, "integrated-sparse-java");
ArrayList
To upsert sparse vectors into an [index of sparse vectors](/guides/index-data/create-an-index#create-an-index-for-sparse-vectors), use the [`upsert`](/reference/api/latest/data-plane/upsert) operation as follows:
* Specify the [`namespace`](/guides/index-data/indexing-overview#namespaces) to upsert into. If the namespace doesn't exist, it is created. To use the default namespace, set the namespace to `"__default__"`.
* Format your input data as records, each with the following:
* An `id` field with a unique record identifier for the index namespace.
* A `sparse_values` field with the sparse vector values and indices.
* Optionally, a `metadata` field with [key-value pairs](/guides/index-data/indexing-overview#metadata) to store additional information or context. When you query the index, you can use metadata to [filter search results](/guides/search/filter-by-metadata).
For example, the following code upserts sparse vector representations of sentences related to the term "apple", with the source text and additional fields stored as metadata:
```python Python theme={null}
from pinecone import Pinecone, SparseValues, Vector
pc = Pinecone(api_key="YOUR_API_KEY")
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
index = pc.Index(host="INDEX_HOST")
index.upsert(
namespace="example-namespace",
vectors=[
{
"id": "vec1",
"sparse_values": {
"values": [1.7958984, 0.41577148, 2.828125, 2.8027344, 2.8691406, 1.6533203, 5.3671875, 1.3046875, 0.49780273, 0.5722656, 2.71875, 3.0820312, 2.5019531, 4.4414062, 3.3554688],
"indices": [822745112, 1009084850, 1221765879, 1408993854, 1504846510, 1596856843, 1640781426, 1656251611, 1807131503, 2543655733, 2902766088, 2909307736, 3246437992, 3517203014, 3590924191]
},
"metadata": {
"chunk_text": "AAPL reported a year-over-year revenue increase, expecting stronger Q3 demand for its flagship phones.",
"category": "technology",
"quarter": "Q3"
}
},
{
"id": "vec2",
"sparse_values": {
"values": [0.4362793, 3.3457031, 2.7714844, 3.0273438, 3.3164062, 5.6015625, 2.4863281, 0.38134766, 1.25, 2.9609375, 0.34179688, 1.4306641, 0.34375, 3.3613281, 1.4404297, 2.2558594, 2.2597656, 4.8710938, 0.5605469],
"indices": [131900689, 592326839, 710158994, 838729363, 1304885087, 1640781426, 1690623792, 1807131503, 2066971792, 2428553208, 2548600401, 2577534050, 3162218338, 3319279674, 3343062801, 3476647774, 3485013322, 3517203014, 4283091697]
},
"metadata": {
"chunk_text": "Analysts suggest that AAPL'\''s upcoming Q4 product launch event might solidify its position in the premium smartphone market.",
"category": "technology",
"quarter": "Q4"
}
},
{
"id": "vec3",
"sparse_values": {
"values": [2.6875, 4.2929688, 3.609375, 3.0722656, 2.1152344, 5.78125, 3.7460938, 3.7363281, 1.2695312, 3.4824219, 0.7207031, 0.0826416, 4.671875, 3.7011719, 2.796875, 0.61621094],
"indices": [8661920, 350356213, 391213188, 554637446, 1024951234, 1640781426, 1780689102, 1799010313, 2194093370, 2632344667, 2641553256, 2779594451, 3517203014, 3543799498, 3837503950, 4283091697]
},
"metadata": {
"chunk_text": "AAPL'\''s strategic Q3 partnerships with semiconductor suppliers could mitigate component risks and stabilize iPhone production",
"category": "technology",
"quarter": "Q3"
}
},
{
"id": "vec4",
"sparse_values": {
"values": [0.73046875, 0.46972656, 2.84375, 5.2265625, 3.3242188, 1.9863281, 0.9511719, 0.5019531, 4.4257812, 3.4277344, 0.41308594, 4.3242188, 2.4179688, 3.1757812, 1.0224609, 2.0585938, 2.5859375],
"indices": [131900689, 152217691, 441495248, 1640781426, 1851149807, 2263326288, 2502307765, 2641553256, 2684780967, 2966813704, 3162218338, 3283104238, 3488055477, 3530642888, 3888762515, 4152503047, 4177290673]
},
"metadata": {
"chunk_text": "AAPL may consider healthcare integrations in Q4 to compete with tech rivals entering the consumer wellness space.",
"category": "technology",
"quarter": "Q4"
}
}
]
)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' });
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
const index = pc.index("INDEX_NAME", "INDEX_HOST")
await index.namespace('example-namespace').upsert({ records: [
{
id: 'vec1',
sparseValues: {
indices: [822745112, 1009084850, 1221765879, 1408993854, 1504846510, 1596856843, 1640781426, 1656251611, 1807131503, 2543655733, 2902766088, 2909307736, 3246437992, 3517203014, 3590924191],
values: [1.7958984, 0.41577148, 2.828125, 2.8027344, 2.8691406, 1.6533203, 5.3671875, 1.3046875, 0.49780273, 0.5722656, 2.71875, 3.0820312, 2.5019531, 4.4414062, 3.3554688]
},
metadata: {
chunk_text: 'AAPL reported a year-over-year revenue increase, expecting stronger Q3 demand for its flagship phones.',
category: 'technology',
quarter: 'Q3'
}
},
{
id: 'vec2',
sparseValues: {
indices: [131900689, 592326839, 710158994, 838729363, 1304885087, 1640781426, 1690623792, 1807131503, 2066971792, 2428553208, 2548600401, 2577534050, 3162218338, 3319279674, 3343062801, 3476647774, 3485013322, 3517203014, 4283091697],
values: [0.4362793, 3.3457031, 2.7714844, 3.0273438, 3.3164062, 5.6015625, 2.4863281, 0.38134766, 1.25, 2.9609375, 0.34179688, 1.4306641, 0.34375, 3.3613281, 1.4404297, 2.2558594, 2.2597656, 4.8710938, 0.5605469]
},
metadata: {
chunk_text: "Analysts suggest that AAPL's upcoming Q4 product launch event might solidify its position in the premium smartphone market.",
category: 'technology',
quarter: 'Q4'
}
},
{
id: 'vec3',
sparseValues: {
indices: [8661920, 350356213, 391213188, 554637446, 1024951234, 1640781426, 1780689102, 1799010313, 2194093370, 2632344667, 2641553256, 2779594451, 3517203014, 3543799498, 3837503950, 4283091697],
values: [2.6875, 4.2929688, 3.609375, 3.0722656, 2.1152344, 5.78125, 3.7460938, 3.7363281, 1.2695312, 3.4824219, 0.7207031, 0.0826416, 4.671875, 3.7011719, 2.796875, 0.61621094]
},
metadata: {
chunk_text: "AAPL's strategic Q3 partnerships with semiconductor suppliers could mitigate component risks and stabilize iPhone production",
category: 'technology',
quarter: 'Q3'
}
},
{
id: 'vec4',
sparseValues: {
indices: [131900689, 152217691, 441495248, 1640781426, 1851149807, 2263326288, 2502307765, 2641553256, 2684780967, 2966813704, 3162218338, 3283104238, 3488055477, 3530642888, 3888762515, 4152503047, 4177290673],
values: [0.73046875, 0.46972656, 2.84375, 5.2265625, 3.3242188, 1.9863281, 0.9511719, 0.5019531, 4.4257812, 3.4277344, 0.41308594, 4.3242188, 2.4179688, 3.1757812, 1.0224609, 2.0585938, 2.5859375]
},
metadata: {
chunk_text: 'AAPL may consider healthcare integrations in Q4 to compete with tech rivals entering the consumer wellness space.',
category: 'technology',
quarter: 'Q4'
}
}
] });
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import io.pinecone.clients.Index;
import com.google.protobuf.Struct;
import com.google.protobuf.Value;
import java.util.*;
public class UpsertSparseVectors {
public static void main(String[] args) throws InterruptedException {
// Instantiate Pinecone class
Pinecone pinecone = new Pinecone.Builder("YOUR_API)KEY").build();
Index index = pinecone.getIndexConnection("docs-example");
// Record 1
ArrayList indices1 = new ArrayList<>(Arrays.asList(
822745112L, 1009084850L, 1221765879L, 1408993854L, 1504846510L,
1596856843L, 1640781426L, 1656251611L, 1807131503L, 2543655733L,
2902766088L, 2909307736L, 3246437992L, 3517203014L, 3590924191L
));
ArrayList values1 = new ArrayList<>(Arrays.asList(
1.7958984f, 0.41577148f, 2.828125f, 2.8027344f, 2.8691406f,
1.6533203f, 5.3671875f, 1.3046875f, 0.49780273f, 0.5722656f,
2.71875f, 3.0820312f, 2.5019531f, 4.4414062f, 3.3554688f
));
Struct metaData1 = Struct.newBuilder()
.putFields("chunk_text", Value.newBuilder().setStringValue("AAPL reported a year-over-year revenue increase, expecting stronger Q3 demand for its flagship phones.").build())
.putFields("category", Value.newBuilder().setStringValue("technology").build())
.putFields("quarter", Value.newBuilder().setStringValue("Q3").build())
.build();
// Record 2
ArrayList indices2 = new ArrayList<>(Arrays.asList(
131900689L, 592326839L, 710158994L, 838729363L, 1304885087L,
1640781426L, 1690623792L, 1807131503L, 2066971792L, 2428553208L,
2548600401L, 2577534050L, 3162218338L, 3319279674L, 3343062801L,
3476647774L, 3485013322L, 3517203014L, 4283091697L
));
ArrayList values2 = new ArrayList<>(Arrays.asList(
0.4362793f, 3.3457031f, 2.7714844f, 3.0273438f, 3.3164062f,
5.6015625f, 2.4863281f, 0.38134766f, 1.25f, 2.9609375f,
0.34179688f, 1.4306641f, 0.34375f, 3.3613281f, 1.4404297f,
2.2558594f, 2.2597656f, 4.8710938f, 0.5605469f
));
Struct metaData2 = Struct.newBuilder()
.putFields("chunk_text", Value.newBuilder().setStringValue("Analysts suggest that AAPL'\\''s upcoming Q4 product launch event might solidify its position in the premium smartphone market.").build())
.putFields("category", Value.newBuilder().setStringValue("technology").build())
.putFields("quarter", Value.newBuilder().setStringValue("Q4").build())
.build();
// Record 3
ArrayList indices3 = new ArrayList<>(Arrays.asList(
8661920L, 350356213L, 391213188L, 554637446L, 1024951234L,
1640781426L, 1780689102L, 1799010313L, 2194093370L, 2632344667L,
2641553256L, 2779594451L, 3517203014L, 3543799498L,
3837503950L, 4283091697L
));
ArrayList values3 = new ArrayList<>(Arrays.asList(
2.6875f, 4.2929688f, 3.609375f, 3.0722656f, 2.1152344f,
5.78125f, 3.7460938f, 3.7363281f, 1.2695312f, 3.4824219f,
0.7207031f, 0.0826416f, 4.671875f, 3.7011719f, 2.796875f,
0.61621094f
));
Struct metaData3 = Struct.newBuilder()
.putFields("chunk_text", Value.newBuilder().setStringValue("AAPL'\\''s strategic Q3 partnerships with semiconductor suppliers could mitigate component risks and stabilize iPhone production").build())
.putFields("category", Value.newBuilder().setStringValue("technology").build())
.putFields("quarter", Value.newBuilder().setStringValue("Q3").build())
.build();
// Record 4
ArrayList indices4 = new ArrayList<>(Arrays.asList(
131900689L, 152217691L, 441495248L, 1640781426L, 1851149807L,
2263326288L, 2502307765L, 2641553256L, 2684780967L, 2966813704L,
3162218338L, 3283104238L, 3488055477L, 3530642888L, 3888762515L,
4152503047L, 4177290673L
));
ArrayList values4 = new ArrayList<>(Arrays.asList(
0.73046875f, 0.46972656f, 2.84375f, 5.2265625f, 3.3242188f,
1.9863281f, 0.9511719f, 0.5019531f, 4.4257812f, 3.4277344f,
0.41308594f, 4.3242188f, 2.4179688f, 3.1757812f, 1.0224609f,
2.0585938f, 2.5859375f
));
Struct metaData4 = Struct.newBuilder()
.putFields("chunk_text", Value.newBuilder().setStringValue("AAPL may consider healthcare integrations in Q4 to compete with tech rivals entering the consumer wellness space").build())
.putFields("category", Value.newBuilder().setStringValue("technology").build())
.putFields("quarter", Value.newBuilder().setStringValue("Q4").build())
.build();
index.upsert("vec1", Collections.emptyList(), indices1, values1, metaData1, "example-namespace");
index.upsert("vec2", Collections.emptyList(), indices2, values2, metaData2, "example-namespace");
index.upsert("vec3", Collections.emptyList(), indices3, values3, metaData3, "example-namespace");
index.upsert("vec4", Collections.emptyList(), indices4, values4, metaData4, "example-namespace");
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
"google.golang.org/protobuf/types/known/structpb"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
idxConnection, err := pc.Index(pinecone.NewIndexConnParams{Host: "INDEX_HOST", Namespace: "example-namespace"})
if err != nil {
log.Fatalf("Failed to create IndexConnection for Host: %v", err)
}
sparseValues1 := pinecone.SparseValues{
Indices: []uint32{822745112, 1009084850, 1221765879, 1408993854, 1504846510, 1596856843, 1640781426, 1656251611, 1807131503, 2543655733, 2902766088, 2909307736, 3246437992, 3517203014, 3590924191},
Values: []float32{1.7958984, 0.41577148, 2.828125, 2.8027344, 2.8691406, 1.6533203, 5.3671875, 1.3046875, 0.49780273, 0.5722656, 2.71875, 3.0820312, 2.5019531, 4.4414062, 3.3554688},
}
metadataMap1 := map[string]interface{}{
"chunk_text": "AAPL reported a year-over-year revenue increase, expecting stronger Q3 demand for its flagship phones",
"category": "technology",
"quarter": "Q3",
}
metadata1, err := structpb.NewStruct(metadataMap1)
if err != nil {
log.Fatalf("Failed to create metadata map: %v", err)
}
sparseValues2 := pinecone.SparseValues{
Indices: []uint32{131900689, 592326839, 710158994, 838729363, 1304885087, 1640781426, 1690623792, 1807131503, 2066971792, 2428553208, 2548600401, 2577534050, 3162218338, 3319279674, 3343062801, 3476647774, 3485013322, 3517203014, 4283091697},
Values: []float32{0.4362793, 3.3457031, 2.7714844, 3.0273438, 3.3164062, 5.6015625, 2.4863281, 0.38134766, 1.25, 2.9609375, 0.34179688, 1.4306641, 0.34375, 3.3613281, 1.4404297, 2.2558594, 2.2597656, 4.8710938, 0.560546},
}
metadataMap2 := map[string]interface{}{
"chunk_text": "Analysts suggest that AAPL's upcoming Q4 product launch event might solidify its position in the premium smartphone market.",
"category": "technology",
"quarter": "Q4",
}
metadata2, err := structpb.NewStruct(metadataMap2)
if err != nil {
log.Fatalf("Failed to create metadata map: %v", err)
}
sparseValues3 := pinecone.SparseValues{
Indices: []uint32{8661920, 350356213, 391213188, 554637446, 1024951234, 1640781426, 1780689102, 1799010313, 2194093370, 2632344667, 2641553256, 2779594451, 3517203014, 3543799498, 3837503950, 4283091697},
Values: []float32{2.6875, 4.2929688, 3.609375, 3.0722656, 2.1152344, 5.78125, 3.7460938, 3.7363281, 1.2695312, 3.4824219, 0.7207031, 0.0826416, 4.671875, 3.7011719, 2.796875, 0.61621094},
}
metadataMap3 := map[string]interface{}{
"chunk_text": "AAPL's strategic Q3 partnerships with semiconductor suppliers could mitigate component risks and stabilize iPhone production",
"category": "technology",
"quarter": "Q3",
}
metadata3, err := structpb.NewStruct(metadataMap3)
if err != nil {
log.Fatalf("Failed to create metadata map: %v", err)
}
sparseValues4 := pinecone.SparseValues{
Indices: []uint32{131900689, 152217691, 441495248, 1640781426, 1851149807, 2263326288, 2502307765, 2641553256, 2684780967, 2966813704, 3162218338, 3283104238, 3488055477, 3530642888, 3888762515, 4152503047, 4177290673},
Values: []float32{0.73046875, 0.46972656, 2.84375, 5.2265625, 3.3242188, 1.9863281, 0.9511719, 0.5019531, 4.4257812, 3.4277344, 0.41308594, 4.3242188, 2.4179688, 3.1757812, 1.0224609, 2.0585938, 2.5859375},
}
metadataMap4 := map[string]interface{}{
"chunk_text": "AAPL may consider healthcare integrations in Q4 to compete with tech rivals entering the consumer wellness space.",
"category": "technology",
"quarter": "Q4",
}
metadata4, err := structpb.NewStruct(metadataMap4)
if err != nil {
log.Fatalf("Failed to create metadata map: %v", err)
}
vectors := []*pinecone.Vector{
{
Id: "vec1",
SparseValues: &sparseValues1,
Metadata: metadata1,
},
{
Id: "vec2",
SparseValues: &sparseValues2,
Metadata: metadata2,
},
{
Id: "vec3",
SparseValues: &sparseValues3,
Metadata: metadata3,
},
{
Id: "vec4",
SparseValues: &sparseValues4,
Metadata: metadata4,
},
}
count, err := idxConnection.UpsertVectors(ctx, vectors)
if err != nil {
log.Fatalf("Failed to upsert vectors: %v", err)
} else {
fmt.Printf("Successfully upserted %d vector(s)!\n", count)
}
}
```
```shell curl theme={null}
INDEX_HOST="INDEX_HOST"
PINECONE_API_KEY="YOUR_API_KEY"
curl "http://$INDEX_HOST/vectors/upsert" \
-H "Content-Type: application/json" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"namespace": "example-namespace",
"vectors": [
{
"id": "vec1",
"sparseValues": {
"values": [1.7958984, 0.41577148, 2.828125, 2.8027344, 2.8691406, 1.6533203, 5.3671875, 1.3046875, 0.49780273, 0.5722656, 2.71875, 3.0820312, 2.5019531, 4.4414062, 3.3554688],
"indices": [822745112, 1009084850, 1221765879, 1408993854, 1504846510, 1596856843, 1640781426, 1656251611, 1807131503, 2543655733, 2902766088, 2909307736, 3246437992, 3517203014, 3590924191]
},
"metadata": {
"chunk_text": "AAPL reported a year-over-year revenue increase, expecting stronger Q3 demand for its flagship phones.",
"category": "technology",
"quarter": "Q3"
}
},
{
"id": "vec2",
"sparseValues": {
"values": [0.4362793, 3.3457031, 2.7714844, 3.0273438, 3.3164062, 5.6015625, 2.4863281, 0.38134766, 1.25, 2.9609375, 0.34179688, 1.4306641, 0.34375, 3.3613281, 1.4404297, 2.2558594, 2.2597656, 4.8710938, 0.5605469],
"indices": [131900689, 592326839, 710158994, 838729363, 1304885087, 1640781426, 1690623792, 1807131503, 2066971792, 2428553208, 2548600401, 2577534050, 3162218338, 3319279674, 3343062801, 3476647774, 3485013322, 3517203014, 4283091697]
},
"metadata": {
"chunk_text": "Analysts suggest that AAPL'\''s upcoming Q4 product launch event might solidify its position in the premium smartphone market.",
"category": "technology",
"quarter": "Q4"
}
},
{
"id": "vec3",
"sparseValues": {
"values": [2.6875, 4.2929688, 3.609375, 3.0722656, 2.1152344, 5.78125, 3.7460938, 3.7363281, 1.2695312, 3.4824219, 0.7207031, 0.0826416, 4.671875, 3.7011719, 2.796875, 0.61621094],
"indices": [8661920, 350356213, 391213188, 554637446, 1024951234, 1640781426, 1780689102, 1799010313, 2194093370, 2632344667, 2641553256, 2779594451, 3517203014, 3543799498, 3837503950, 4283091697]
},
"metadata": {
"chunk_text": "AAPL'\''s strategic Q3 partnerships with semiconductor suppliers could mitigate component risks and stabilize iPhone production",
"category": "technology",
"quarter": "Q3"
}
},
{
"id": "vec4",
"sparseValues": {
"values": [0.73046875, 0.46972656, 2.84375, 5.2265625, 3.3242188, 1.9863281, 0.9511719, 0.5019531, 4.4257812, 3.4277344, 0.41308594, 4.3242188, 2.4179688, 3.1757812, 1.0224609, 2.0585938, 2.5859375],
"indices": [131900689, 152217691, 441495248, 1640781426, 1851149807, 2263326288, 2502307765, 2641553256, 2684780967, 2966813704, 3162218338, 3283104238, 3488055477, 3530642888, 3888762515, 4152503047, 4177290673]
},
"metadata": {
"chunk_text": "AAPL may consider healthcare integrations in Q4 to compete with tech rivals entering the consumer wellness space.",
"category": "technology",
"quarter": "Q4"
}
},
]
}'
```
## Upsert documents
Documents are the unit of data in an index with a document schema; see [Document](/guides/get-started/concepts#document) for the definition. Each field in a document is indexed according to the configuration you declared for it in the schema, not just its type — for example, a `string` field can be indexed for BM25 via the `full_text_search` config, and a separate `dense_vector` field can store vector values you provide at upsert time. Indexes with document schemas do not support integrated inference fields such as `semantic_text`.
The example below upserts two documents into the `articles` namespace using the document API. Each document is indexed for BM25 ranking on `body`. The `category` field is upserted as metadata — it isn't declared in the schema but is auto-indexed for filtering at upsert time:
```bash theme={null}
curl -X POST "https://INDEX_HOST/namespaces/articles/documents/upsert" \
-H "Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "X-Pinecone-Api-Version: 2026-01.alpha" \
-d '{
"documents": [
{
"_id": "doc1",
"body": "Pinecone serverless indexes scale automatically with your workload.",
"category": "platform"
},
{
"_id": "doc2",
"body": "Full-text search uses BM25 ranking on text fields with full-text search enabled.",
"category": "search"
}
]
}'
```
The document API is in public preview and uses the `2026-01.alpha` API version. Indexes with dense or sparse vectors use the stable `2025-10` API version shown in the upsert examples above.
Field-name rules:
* Fields not declared in the schema are stored on the document, returned via `include_fields`, and automatically indexed for filtering as metadata. The schema declares only ranking fields (FTS-enabled `string`, `dense_vector`, `sparse_vector`).
* Field names must be unique, non-empty strings, must not start with `_` (reserved for system-managed fields like `_id` and `_score`) or `$` (reserved for filter operators), and are limited to 64 bytes.
Document upsert limits:
* Each upsert request can contain up to 1000 documents and must be no larger than 2 MB.
* Each document can be no larger than 2 MB.
* Each `full_text_search` string field can be no larger than 100 KB and can contain up to 10,000 tokens.
* Each token can be no larger than 256 bytes before analyzer truncation.
* Metadata fields on a document (everything outside FTS-enabled `string` fields) are limited to 40 KB per document in total. This limit does not apply to `full_text_search` text fields.
For the full upsert reference (SDK examples, batching, and the response schema), see [Full-text search](/guides/search/full-text-search).
## Upsert in batches
To control costs when ingesting large datasets (10,000,000+ records), use [import](/guides/index-data/import-data) instead of upsert.
Send upserts in batches to help increase throughput.
* When upserting records with vectors, a batch should be as large as possible (up to 1000 records) without exceeding the [max request size of 2 MB](#upsert-limits).
To understand the number of records you can fit into one batch based on the vector dimensions and metadata size, see the following table:
| Dimension | Metadata (bytes) | Max batch size |
| :-------- | :--------------- | :------------- |
| 386 | 0 | 1000 |
| 768 | 500 | 559 |
| 1536 | 2000 | 245 |
* When upserting records with text, a batch can contain up to 96 records. This limit comes from the [hosted embedding models](/guides/index-data/create-an-index#embedding-models) used during integrated embedding rather than the batch size limit for upserting raw vectors.
```Python Python theme={null}
import random
import itertools
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
index = pc.Index(host="INDEX_HOST")
def chunks(iterable, batch_size=200):
"""A helper function to break an iterable into chunks of size batch_size."""
it = iter(iterable)
chunk = tuple(itertools.islice(it, batch_size))
while chunk:
yield chunk
chunk = tuple(itertools.islice(it, batch_size))
vector_dim = 128
vector_count = 10000
# Example generator that generates many (id, vector) pairs
example_data_generator = map(lambda i: (f'id-{i}', [random.random() for _ in range(vector_dim)]), range(vector_count))
# Upsert data with 200 vectors per upsert request
for ids_vectors_chunk in chunks(example_data_generator, batch_size=200):
index.upsert(vectors=ids_vectors_chunk)
```
```JavaScript JavaScript theme={null}
import { Pinecone } from "@pinecone-database/pinecone";
const RECORD_COUNT = 10000;
const RECORD_DIMENSION = 128;
const client = new Pinecone({ apiKey: "YOUR_API_KEY" });
const index = client.index("docs-example");
// A helper function that breaks an array into chunks of size batchSize
const chunks = (array, batchSize = 200) => {
const chunks = [];
for (let i = 0; i < array.length; i += batchSize) {
chunks.push(array.slice(i, i + batchSize));
}
return chunks;
};
// Example data generation function, creates many (id, vector) pairs
const generateExampleData = () =>
Array.from({ length: RECORD_COUNT }, (_, i) => {
return {
id: `id-${i}`,
values: Array.from({ length: RECORD_DIMENSION }, (_, i) => Math.random()),
};
});
const exampleRecordData = generateExampleData();
const recordChunks = chunks(exampleRecordData);
// Upsert data with 200 records per upsert request
for (const chunk of recordChunks) {
await index.upsert({ records: chunk })
}
```
```java Java theme={null}
import io.pinecone.clients.Index;
import io.pinecone.configs.PineconeConfig;
import io.pinecone.configs.PineconeConnection;
import io.pinecone.unsigned_indices_model.VectorWithUnsignedIndices;
import java.util.Arrays;
import java.util.List;
public class UpsertBatchExample {
public static void main(String[] args) {
PineconeConfig config = new PineconeConfig("YOUR_API_KEY");
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
config.setHost("INDEX_HOST");
PineconeConnection connection = new PineconeConnection(config);
Index index = new Index(connection, "INDEX_NAME");
ArrayList vectors = generateVectors();
ArrayList> chunks = chunks(vectors, BATCH_SIZE);
for (ArrayList chunk : chunks) {
index.upsert(chunk, "example-namespace");
}
}
// A helper function that breaks an ArrayList into chunks of batchSize
private static ArrayList> chunks(ArrayList vectors, int batchSize) {
ArrayList> chunks = new ArrayList<>();
ArrayList chunk = new ArrayList<>();
for (int i = 0; i < vectors.size(); i++) {
if (i % BATCH_SIZE == 0 && i != 0) {
chunks.add(chunk);
chunk = new ArrayList<>();
}
chunk.add(vectors.get(i));
}
return chunks;
}
// Example data generation function, creates many (id, vector) pairs
private static ArrayList generateVectors() {
Random random = new Random();
ArrayList vectors = new ArrayList<>();
for (int i = 0; i <= RECORD_COUNT; i++) {
String id = "id-" + i;
ArrayList values = new ArrayList<>();
for (int j = 0; j < RECORD_DIMENSION; j++) {
values.add(random.nextFloat());
}
VectorWithUnsignedIndices vector = new VectorWithUnsignedIndices();
vector.setId(id);
vector.setValues(values);
vectors.add(vector);
}
return vectors;
}
}
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
idxConnection, err := pc.Index(pinecone.NewIndexConnParams{Host: "INDEX_HOST"})
if err != nil {
log.Fatalf("Failed to create IndexConnection for Host: %v", err)
}
// Generate a large number of vectors to upsert
vectorCount := 10000
vectorDim := idx.Dimension
vectors := make([]*pinecone.Vector, vectorCount)
for i := 0; i < int(vectorCount); i++ {
randomFloats := make([]float32, vectorDim)
for i := int32(0); i < vectorDim; i++ {
randomFloats[i] = rand.Float32()
}
vectors[i] = &pinecone.Vector{
Id: fmt.Sprintf("doc1#-vector%d", i),
Values: randomFloats,
}
}
// Break the vectors into batches of 200
var batches [][]*pinecone.Vector
batchSize := 200
for len(vectors) > 0 {
batchEnd := batchSize
if len(vectors) < batchSize {
batchEnd = len(vectors)
}
batches = append(batches, vectors[:batchEnd])
vectors = vectors[batchEnd:]
}
// Upsert batches
for i, batch := range batches {
upsertResp, err := idxConn.UpsertVectors(context.Background(), batch)
if err != nil {
panic(err)
}
fmt.Printf("upserted %d vectors (%v of %v batches)\n", upsertResp, i+1, len(batches))
}
}
```
## Upsert in parallel
Python SDK v6.0.0 and later provide `async` methods for use with [asyncio](https://docs.python.org/3/library/asyncio.html). Asyncio support makes it possible to use Pinecone with modern async web frameworks such as FastAPI, Quart, and Sanic. For more details, see [Async requests](/reference/sdks/python/overview#async-requests).
Send multiple upserts in parallel to help increase throughput. Vector operations block until the response has been received. However, they can be made asynchronously as follows:
```Python Python theme={null}
# This example uses `async_req=True` and multiple threads.
# For a single-threaded approach compatible with modern async web frameworks,
# see https://docs.pinecone.io/reference/sdks/python/overview#async-requests
import random
import itertools
from pinecone import Pinecone
# Initialize the client with pool_threads=30. This limits simultaneous requests to 30.
pc = Pinecone(api_key="YOUR_API_KEY", pool_threads=30)
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
index = pc.Index(host="INDEX_HOST")
def chunks(iterable, batch_size=200):
"""A helper function to break an iterable into chunks of size batch_size."""
it = iter(iterable)
chunk = tuple(itertools.islice(it, batch_size))
while chunk:
yield chunk
chunk = tuple(itertools.islice(it, batch_size))
vector_dim = 128
vector_count = 10000
example_data_generator = map(lambda i: (f'id-{i}', [random.random() for _ in range(vector_dim)]), range(vector_count))
# Upsert data with 200 vectors per upsert request asynchronously
# - Pass async_req=True to index.upsert()
with pc.Index(host="INDEX_HOST", pool_threads=30) as index:
# Send requests in parallel
async_results = [
index.upsert(vectors=ids_vectors_chunk, async_req=True)
for ids_vectors_chunk in chunks(example_data_generator, batch_size=200)
]
# Wait for and retrieve responses (this raises in case of error)
[async_result.get() for async_result in async_results]
```
```JavaScript JavaScript theme={null}
import { Pinecone } from "@pinecone-database/pinecone";
const RECORD_COUNT = 10000;
const RECORD_DIMENSION = 128;
const client = new Pinecone({ apiKey: "YOUR_API_KEY" });
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
const index = pc.index("INDEX_NAME", "INDEX_HOST")
// A helper function that breaks an array into chunks of size batchSize
const chunks = (array, batchSize = 200) => {
const chunks = [];
for (let i = 0; i < array.length; i += batchSize) {
chunks.push(array.slice(i, i + batchSize));
}
return chunks;
};
// Example data generation function, creates many (id, vector) pairs
const generateExampleData = () =>
Array.from({ length: RECORD_COUNT }, (_, i) => {
return {
id: `id-${i}`,
values: Array.from({ length: RECORD_DIMENSION }, (_, i) => Math.random()),
};
});
const exampleRecordData = generateExampleData();
const recordChunks = chunks(exampleRecordData);
// Upsert data with 200 records per request asynchronously using Promise.all()
await Promise.all(recordChunks.map((chunk) => index.upsert({ records: chunk })));
```
```java Java theme={null}
import com.google.protobuf.Struct;
import com.google.protobuf.Value;
import io.pinecone.clients.Index;
import io.pinecone.configs.PineconeConfig;
import io.pinecone.configs.PineconeConnection;
import io.pinecone.proto.UpsertResponse;
import io.pinecone.unsigned_indices_model.VectorWithUnsignedIndices;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.List;
public class UpsertExample {
public static void main(String[] args) {
PineconeConfig config = new PineconeConfig("YOUR_API_KEY");
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
config.setHost("INDEX_HOST");
PineconeConnection connection = new PineconeConnection(config);
Index index = new Index(connection, "INDEX_NAME");
// Run 5 threads concurrently and upsert data into pinecone
int numberOfThreads = 5;
// Create a fixed thread pool
ExecutorService executor = Executors.newFixedThreadPool(numberOfThreads);
// Submit tasks to the executor
for (int i = 0; i < numberOfThreads; i++) {
// upsertData
int batchNumber = i+1;
executor.submit(() -> upsertData(index, batchNumber));
}
// Shutdown the executor
executor.shutdown();
}
private static void upsertData(Index index, int batchNumber) {
// Vector ids to be upserted
String prefix = "v" + batchNumber;
List upsertIds = Arrays.asList(prefix + "_1", prefix + "_2", prefix + "_3");
// List of values to be upserted
List> values = new ArrayList<>();
values.add(Arrays.asList(1.0f, 2.0f, 3.0f));
values.add(Arrays.asList(4.0f, 5.0f, 6.0f));
values.add(Arrays.asList(7.0f, 8.0f, 9.0f));
// List of sparse indices to be upserted
List> sparseIndices = new ArrayList<>();
sparseIndices.add(Arrays.asList(1L, 2L, 3L));
sparseIndices.add(Arrays.asList(4L, 5L, 6L));
sparseIndices.add(Arrays.asList(7L, 8L, 9L));
// List of sparse values to be upserted
List> sparseValues = new ArrayList<>();
sparseValues.add(Arrays.asList(1000f, 2000f, 3000f));
sparseValues.add(Arrays.asList(4000f, 5000f, 6000f));
sparseValues.add(Arrays.asList(7000f, 8000f, 9000f));
List vectors = new ArrayList<>(3);
// Metadata to be upserted
Struct metadataStruct1 = Struct.newBuilder()
.putFields("genre", Value.newBuilder().setStringValue("action").build())
.putFields("year", Value.newBuilder().setNumberValue(2019).build())
.build();
Struct metadataStruct2 = Struct.newBuilder()
.putFields("genre", Value.newBuilder().setStringValue("thriller").build())
.putFields("year", Value.newBuilder().setNumberValue(2020).build())
.build();
Struct metadataStruct3 = Struct.newBuilder()
.putFields("genre", Value.newBuilder().setStringValue("comedy").build())
.putFields("year", Value.newBuilder().setNumberValue(2021).build())
.build();
List metadataStructList = Arrays.asList(metadataStruct1, metadataStruct2, metadataStruct3);
// Upsert data
for (int i = 0; i < metadataStructList.size(); i++) {
vectors.add(buildUpsertVectorWithUnsignedIndices(upsertIds.get(i), values.get(i), sparseIndices.get(i), sparseValues.get(i), metadataStructList.get(i)));
}
UpsertResponse upsertResponse = index.upsert(vectors, "example-namespace");
}
}
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"math/rand"
"sync"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
idxConn, err := pc.Index(pinecone.NewIndexConnParams{Host: "INDEX_HOST"})
if err != nil {
log.Fatalf("Failed to create IndexConnection for Host: %v", err)
}
// Generate a large number of vectors to upsert
vectorCount := 10000
vectorDim := idx.Dimension
vectors := make([]*pinecone.Vector, vectorCount)
for i := 0; i < int(vectorCount); i++ {
randomFloats := make([]float32, vectorDim)
for i := int32(0); i < vectorDim; i++ {
randomFloats[i] = rand.Float32()
}
vectors[i] = &pinecone.Vector{
Id: fmt.Sprintf("doc1#-vector%d", i),
Values: randomFloats,
}
}
// Break the vectors into batches of 200
var batches [][]*pinecone.Vector
batchSize := 200
for len(vectors) > 0 {
batchEnd := batchSize
if len(vectors) < batchSize {
batchEnd = len(vectors)
}
batches = append(batches, vectors[:batchEnd])
vectors = vectors[batchEnd:]
}
// Use channels to manage concurrency and possible errors
maxConcurrency := 10
errChan := make(chan error, len(batches))
semaphore := make(chan struct{}, maxConcurrency)
var wg sync.WaitGroup
for i, batch := range batches {
wg.Add(1)
semaphore <- struct{}{}
go func(batch []*pinecone.Vector, i int) {
defer wg.Done()
defer func() { <-semaphore }()
upsertResp, err := idxConn.UpsertVectors(context.Background(), batch)
if err != nil {
errChan <- fmt.Errorf("batch %d failed: %v", i, err)
return
}
fmt.Printf("upserted %d vectors (%v of %v batches)\n", upsertResp, i+1, len(batches))
}(batch, i)
}
wg.Wait()
close(errChan)
for err := range errChan {
if err != nil {
fmt.Printf("Error while upserting batch: %v\n", err)
}
}
}
```
### Python SDK with gRPC
Using the Python SDK with gRPC extras can provide higher upsert speeds. Through multiplexing, gRPC is able to handle large amounts of requests in parallel without slowing down the rest of the system (HoL blocking), unlike REST. Moreover, you can pass various retry strategies to the gRPC SDK, including [exponential backoff](/guides/production/error-handling#implement-retry-logic).
To install the gRPC version of the SDK:
```Shell Shell theme={null}
pip install "pinecone[grpc]"
```
To use the gRPC SDK, import the `pinecone.grpc` subpackage and target an index as usual:
```Python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
# This is gRPC client aliased as "Pinecone"
pc = Pinecone(api_key='YOUR_API_KEY')
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
index = pc.Index(host="INDEX_HOST")
```
To launch multiple read and write requests in parallel, pass `async_req` to the `upsert` operation:
```Python Python theme={null}
def chunker(seq, batch_size):
return (seq[pos:pos + batch_size] for pos in range(0, len(seq), batch_size))
async_results = [
index.upsert(vectors=chunk, async_req=True)
for chunk in chunker(data, batch_size=200)
]
# Wait for and retrieve responses (in case of error)
[async_result.result() for async_result in async_results]
```
It is possible to get write-throttled faster when upserting using the gRPC SDK. If you see this often, [implement retry logic with exponential backoff](/guides/production/error-handling#implement-retry-logic) while upserting.
The syntax for upsert, query, fetch, and delete with the gRPC SDK remain the same as the standard SDK.
## Upsert limits
| Metric | Limit |
| :----------------------------------------------------------------- | :------------------------------------------------------------ |
| Max [batch size](/guides/index-data/upsert-data#upsert-in-batches) | 2 MB or 1000 records with vectors 96 records with text |
| Max documents per upsert request | 1000 |
| Max document upsert request size | 2 MB |
| Max document size | 2 MB |
| Max `full_text_search` string fields per schema | 100 |
| Max size per `full_text_search` string field | 100 KB |
| Max tokens per `full_text_search` string field | 10,000 |
| Max bytes per token | 256 bytes |
| Max filterable metadata size per document | 40 KB |
| Max length for a record ID | 512 characters |
| Max dimensionality for dense vectors | 20,000 |
| Max non-zero values for sparse vectors | 2048 |
| Max dimensionality for sparse vectors | 4.2 billion |
The 40 KB filterable metadata limit does not apply to `full_text_search` text fields.
# Back up a pod-based index
Source: https://docs.pinecone.io/guides/indexes/pods/back-up-a-pod-based-index
Legacy guide for backing up Pinecone pod-based indexes using collections. Collections are a pod-only feature not available for serverless indexes.
Customers who sign up for a Standard or Enterprise plan on or after August 18, 2025 cannot create pod-based indexes. Instead, create [serverless indexes](/guides/index-data/create-an-index), and consider using [dedicated read nodes](/guides/index-data/dedicated-read-nodes) for large workloads (millions of records or more, and moderate or high query rates).
This page describes how to create a static copy of a pod-based index, also known as a [collection](/guides/indexes/pods/understanding-collections).
## Create a collection
To create a backup of your pod-based index, use the [`create_collection`](/reference/api/latest/control-plane/create_collection) operation.
The following example creates a [collection](/guides/indexes/pods/understanding-collections) named `example-collection` from an index named `docs-example`:
```python Python theme={null}
# pip install "pinecone[grpc]"
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="API_KEY")
pc.create_collection("example-collection", "docs-example")
```
```javascript JavaScript theme={null}
// npm install @pinecone-database/pinecone
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({
apiKey: 'YOUR_API_KEY'
});
await pc.createCollection({
name: "example-collection",
source: "docs-example",
});
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
public class CreateCollectionExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
pc.createCollection("example-collection", "docs-example");
}
}
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
collection, err := pc.CreateCollection(ctx, &pinecone.CreateCollectionRequest{
Name: "example-collection",
Source: "docs-example",
})
if err != nil {
log.Fatalf("Failed to create collection: %v", err)
} else {
fmt.Printf("Successfully created collection: %v", collection.Name)
}
}
```
```shell curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -s POST "https://api.pinecone.io/collections" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"name": "example-collection",
"source": "docs-example"
}'
```
You can create a collection using the [Pinecone console](https://app.pinecone.io/organizations/-/projects/-/backups).
## Check the status of a collection
To retrieve the status of the process creating a collection and the size of the collection, use the [`describe_collection`](/reference/api/latest/control-plane/describe_collection) operation. Specify the name of the collection to check. You can only call `describe_collection` on a collection in the current project.
The `describe_collection` operation returns an object containing key-value pairs representing the name of the collection, the size in bytes, and the creation status of the collection.
The following example gets the creation status and size of a collection named `example-collection`.
```python Python theme={null}
# pip install "pinecone[grpc]"
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key='API_KEY')
pc.describe_collection(name="example-collection")
```
```javascript JavaScript theme={null}
// npm install @pinecone-database/pinecone
import { Pinecone } from '@pinecone-database/pinecone';
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' });
await pc.describeCollection('example-collection');
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.client.model.CollectionModel;
public class DescribeCollectionExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
CollectionModel collectionModel = pc.describeCollection("example-collection");
System.out.println(collectionModel);
}
}
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
collectionName := "example-collection"
collection, err := pc.DescribeCollection(ctx, collectionName)
if err != nil {
log.Fatalf("Error describing collection %v: %v", collectionName, err)
} else {
fmt.Printf("Collection: %+v", collection)
}
}
```
```shell curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -i -X GET "https://api.pinecone.io/collections/example-collection" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10"
```
You can check the status of a collection using the [Pinecone console](https://app.pinecone.io/organizations/-/projects/-/backups).
## List your collections
To get a list of the collections in the current project, use the [`list_collections`](/reference/api/latest/control-plane/list_collections) operation.
```python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key='API_KEY')
pc.list_collections()
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' })
await pc.listCollections();
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.client.model.CollectionModel;
public class ListCollectionsExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
List collectionList = pc.listCollections().getCollections();
}
}
```
```go Go theme={null}
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func prettifyStruct(obj interface{}) string {
bytes, _ := json.MarshalIndent(obj, "", " ")
return string(bytes)
}
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
collections, err := pc.ListCollections(ctx)
if err != nil {
log.Fatalf("Failed to list collections: %v", err)
} else {
if len(collections) == 0 {
fmt.Printf("No collections found in project")
} else {
for _, collection := range collections {
fmt.Printf("collection: %v\n", prettifyStruct(collection))
}
}
}
}
```
```shell curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -i -X GET "https://api.pinecone.io/collections" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10"
```
You can view a list of your collections using the [Pinecone console](https://app.pinecone.io/organizations/-/projects/-/backups).
You can view a list of your collections using the [Pinecone console](https://app.pinecone.io/organizations/-/projects/-/backups).
## Delete a collection
To delete a collection, use the [`delete_collection`](/reference/api/latest/control-plane/delete_collection) operation. Specify the name of the collection to delete.
Deleting the collection takes several minutes. During this time, the [`describe_collection`](#check-the-status-of-a-collection) operation returns the status "deleting".
```python Python theme={null}
# pip install "pinecone[grpc]"
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key='API_KEY')
pc.delete_collection("example-collection")
```
```javascript JavaScript theme={null}
// npm install @pinecone-database/pinecone
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' })
await pc.deleteCollection("example-collection");
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
public class DeleteCollectionExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
pc.deleteCollection("example-collection");
}
}
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
collectionName := "example-collection"
err = pc.DeleteCollection(ctx, collectionName)
if err != nil {
log.Fatalf("Failed to delete collection: %v\n", err)
} else {
if len(collections) == 0 {
fmt.Printf("No collections found in project")
} else {
fmt.Printf("Successfully deleted collection \"%v\"\n", collectionName)
}
}
}
```
```shell curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -i -X DELETE "https://api.pinecone.io/collections/example-collection" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10"
```
You can delete a collection using the [Pinecone console](https://app.pinecone.io/organizations/-/projects/-/backups).
# Choose a pod type and size
Source: https://docs.pinecone.io/guides/indexes/pods/choose-a-pod-type-and-size
Choose a Pinecone pod type and size (s1, p1, p2). Legacy guide: pods are unavailable to new customers as of August 2025; serverless needs no planning.
Customers who sign up for a Standard or Enterprise plan on or after August 18, 2025 cannot create pod-based indexes. Instead, create [serverless indexes](/guides/index-data/create-an-index), and consider using [dedicated read nodes](/guides/index-data/dedicated-read-nodes) for large workloads (millions of records or more, and moderate or high query rates).
When planning your Pinecone deployment, it is important to understand the approximate storage requirements of your vectors to choose the appropriate pod type and number. This page will give guidance on sizing to help you plan accordingly.
As with all guidelines, these considerations are general and may not apply to your specific use case. We caution you to always test your deployment and ensure that the index configuration you are using is appropriate to your requirements.
[Collections](/guides/indexes/pods/understanding-collections) allow you to create new versions of your index with different pod types and sizes. This also allows you to test different configurations. This guide is merely an overview of sizing considerations; test your index configuration before moving to production.
Users on Standard and Enterprise plans can [contact Support](https://app.pinecone.io/organizations/-/settings/support/ticket) for further help with sizing and testing.
## Overview
There are five main considerations when deciding how to configure your Pinecone index:
* Number of vectors
* Dimensionality of your vectors
* Size of metadata on each vector
* Queries per second (QPS) throughput
* Cardinality of indexed metadata
Each of these considerations comes with requirements for index size, pod type, and replication strategy.
### Number of vectors
The most important consideration in sizing is the [number of vectors](/guides/index-data/upsert-data) you plan on working with. As a rule of thumb, a single p1 pod can store approximately 1M vectors, while a s1 pod can store 5M vectors. However, this can be affected by other factors, such as dimensionality and metadata, which are explained below.
### Dimensionality of vectors
The rules of thumb above for how many vectors can be stored in a given pod assumes a typical configuration of 768 [dimensions per vector](/guides/index-data/create-an-index). As your individual use case will dictate the dimensionality of your vectors, the amount of space required to store them may necessarily be larger or smaller.
Each dimension on a single vector consumes 4 bytes of memory and storage per dimension, so if you expect to have 1M vectors with 768 dimensions each, that’s about 3GB of storage without factoring in metadata or other overhead. Using that reference, we can estimate the typical pod size and number needed for a given index. Table 1 below gives some examples of this.
**Table 1: Estimated number of pods per 1M vectors by dimensionality**
| Pod type | Dimensions | Estimated max vectors per pod |
| -------- | ---------: | ----------------------------: |
| **p1** | 512 | 1,250,000 |
| | 768 | 1,000,000 |
| | 1024 | 675,000 |
| | 1536 | 500,000 |
| **p2** | 512 | 1,250,000 |
| | 768 | 1,100,000 |
| | 1024 | 1,000,000 |
| | 1536 | 550,000 |
| **s1** | 512 | 8,000,000 |
| | 768 | 5,000,000 |
| | 1024 | 4,000,000 |
| | 1536 | 2,500,000 |
Pinecone does not support fractional pod deployments, so always round up to the next nearest whole number when choosing your pods.
## Queries per second (QPS)
QPS speeds are governed by a combination of the [pod type](/guides/indexes/pods/understanding-pod-based-indexes#pod-types) of the index, the number of [replicas](/guides/indexes/pods/scale-pod-based-indexes#add-replicas), and the `top_k` value of queries. The pod type is the primary factor driving QPS, as the different pod types are optimized for different approaches.
The [p1 pods](/guides/index-data/indexing-overview/#p1-pods) are performance-optimized pods which provide very low query latencies, but hold fewer vectors per pod than [s1 pods](/guides/index-data/indexing-overview/#s1-pods). They are ideal for applications with low latency requirements (\<100ms). The s1 pods are optimized for storage and provide large storage capacity and lower overall costs with slightly higher query latencies than p1 pods. They are ideal for very large indexes with moderate or relaxed latency requirements.
The [p2 pod type](/guides/index-data/indexing-overview/#p2-pods) provides greater query throughput with lower latency. They support 200 QPS per replica and return queries in less than 10ms. This means that query throughput and latency are better than s1 and p1, especially for low dimension vectors (\<512D).
As a rule, a single p1 pod with 1M vectors of 768 dimensions each and no replicas can handle about 20 QPS. It’s possible to get greater or lesser speeds, depending on the size of your metadata, number of vectors, the dimensionality of your vectors, and the `top_K` value for your search. See Table 2 below for more examples.
**Table 2: QPS by pod type and `top_k` value**\*
| Pod type | top\_k 10 | top\_k 250 | top\_k 1000 |
| -------- | --------- | ---------- | ----------- |
| p1 | 30 | 25 | 20 |
| p2 | 150 | 50 | 20 |
| s1 | 10 | 10 | 10 |
\*The QPS values in Table 2 represent baseline QPS with 1M vectors and 768 dimensions.
[Adding replicas](/guides/indexes/pods/scale-pod-based-indexes#add-replicas) is the simplest way to increase your QPS. Each replica increases the throughput potential by roughly the same QPS, so aiming for 150 QPS using p1 pods means using the primary pod and 5 replicas. Using threading or multiprocessing in your application is also important, as issuing single queries sequentially still subjects you to delays from any underlying latency. The [Pinecone gRPC SDK](/guides/index-data/upsert-data#grpc-python-sdk) can also be used to increase throughput of upserts.
### Metadata cardinality and size
The last consideration when planning your indexes is the cardinality and size of your [metadata](/guides/index-data/upsert-data#inserting-vectors-with-metadata). While the increases are small when talking about a few million vectors, they can have a real impact as you grow to hundreds of millions or billions of vectors.
Indexes with very high cardinality, like those storing a unique user ID on each vector, can have significant memory requirements, resulting in fewer vectors fitting per pod. Also, if the size of the metadata per vector is larger, the index requires more storage. Limiting which metadata fields are indexed using [selective metadata indexing](/guides/indexes/pods/manage-pod-based-indexes#selective-metadata-indexing) can help lower memory usage.
### Pod sizes
You can also start with one of the larger [pod sizes](/guides/index-data/indexing-overview/#pod-size-and-performance), like p1.x2. Each step up in pod size doubles the space available for your vectors. We recommend starting with x1 pods and scaling as you grow. This way, you don’t start with too large a pod size and have nowhere else to go up, meaning you have to migrate to a new index before you’re ready.
### Example applications
The following examples will showcase how to use the sizing guidelines above to choose the appropriate type, size, and number of pods for your index.
#### Example 1: Semantic search of news articles
In our first example, we’ll use the demo app for semantic search from our documentation. In this case, we’re only working with 204,135 vectors. The vectors use 300 dimensions each, well under the general measure of 768 dimensions. Using the rule of thumb above of up to 1M vectors per p1 pod, we can run this app comfortably with a single p1.x1 pod.
#### Example 2: Facial recognition
For this example, suppose you’re building an application to identify customers using facial recognition for a secure banking app. Facial recognition can work with as few as 128 dimensions, but in this case, because the app will be used for access to finances, we want to make sure we’re certain that the person using it is the right one. We plan for 100M customers and use 2048 dimensions per vector.
We know from our rules of thumb above that 1M vectors with 768 dimensions fit nicely in a p1.x1 pod. We can just divide those numbers into the new targets to get the ratios we’ll need for our pod estimate:
```
100M / 1M = 100 base p1 pods
2048 / 768 = 2.667 vector ratio
2.667 * 100 = 267 rounding up
```
So we need 267 p1.x1 pods. We can reduce that by switching to s1 pods instead, sacrificing latency by increasing storage availability. They hold five times the storage of p1.x1, so the math is simple:
```
267 / 5 = 54 rounding up
```
So we estimate that we need 54 s1.x1 pods to store very high dimensional data for the face of each of the bank’s customers.
# Create a pod-based index
Source: https://docs.pinecone.io/guides/indexes/pods/create-a-pod-based-index
Create a Pinecone pod-based index. Legacy guide: new customers cannot create pod indexes as of August 2025; use serverless index creation instead.
Customers who sign up for a Standard or Enterprise plan on or after August 18, 2025 cannot create pod-based indexes. Instead, create [serverless indexes](/guides/index-data/create-an-index), and consider using [dedicated read nodes](/guides/index-data/dedicated-read-nodes) for large workloads (millions of records or more, and moderate or high query rates).
This page shows you how to create a pod-based index. For guidance on serverless indexes, see [Create a serverless index](/guides/index-data/create-an-index).
## Create a pod index
To create a pod index, use the [`create_index`](/reference/api/latest/control-plane/create_index) operation as follows:
* Provide a `name` for the index.
* Specify the `dimension` and `metric` of the vectors you'll store in the index. This should match the dimension and metric supported by your embedding model.
* Set `spec.environment` to the [environment](/guides/index-data/create-an-index#cloud-regions) where the index should be deployed. For Python, you also need to import the `ServerlessSpec` class.
* Set `spec.pod_type` to the [pod type](/guides/indexes/pods/understanding-pod-based-indexes#pod-types) and [size](/guides/index-data/indexing-overview#pod-size-and-performance) that you want.
Other parameters are optional. See the [API reference](/reference/api/latest/control-plane/create_index) for details.
```Python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone, PodSpec
pc = Pinecone(api_key="YOUR_API_KEY")
pc.create_index(
name="docs-example",
dimension=1536,
metric="cosine",
spec=PodSpec(
environment="us-west1-gcp",
pod_type="p1.x1",
pods=1
),
deletion_protection="disabled"
)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({
apiKey: 'YOUR_API_KEY'
});
await pc.createIndex({
name: 'docs-example',
dimension: 1536,
metric: 'cosine',
spec: {
pod: {
environment: 'us-west1-gcp',
podType: 'p1.x1',
pods: 1
}
},
deletionProtection: 'disabled',
});
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.model.IndexModel;
import org.openapitools.db_control.client.model.DeletionProtection;
public class CreateIndexExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
pc.createPodsIndex("docs-example", 1536, "us-west1-gcp",
"p1.x1", "cosine", DeletionProtection.DISABLED);
}
}
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
indexName := "docs-example"
metric := pinecone.Dotproduct
deletionProtection := pinecone.DeletionProtectionDisabled
idx, err := pc.CreatePodIndex(ctx, &pinecone.CreatePodIndexRequest{
Name: indexName,
Metric: &metric,
Dimension: 1536,
Environment: "us-east1-gcp",
PodType: "p1.x1",
DeletionProtection: &deletionProtection,
})
if err != nil {
log.Fatalf("Failed to create pod-based index: %v", idx.Name)
} else {
fmt.Printf("Successfully created pod-based index: %v", idx.Name)
}
}
```
```bash curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -s "https://api.pinecone.io/indexes" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"name": "docs-example",
"dimension": 1536,
"metric": "cosine",
"spec": {
"pod": {
"environment": "us-west1-gcp",
"pod_type": "p1.x1",
"pods": 1
}
},
"deletion_protection": "disabled"
}'
```
## Create a pod index from a collection
You can create a pod-based index from a collection. For more details, see [Restore an index](/guides/indexes/pods/restore-a-pod-based-index).
# Manage pod-based indexes
Source: https://docs.pinecone.io/guides/indexes/pods/manage-pod-based-indexes
Manage Pinecone pod-based indexes. Legacy guide: pod indexes are unavailable to new customers as of August 2025; serverless is recommended for new projects.
Customers who sign up for a Standard or Enterprise plan on or after August 18, 2025 cannot create pod-based indexes. Instead, create [serverless indexes](/guides/index-data/create-an-index), and consider using [dedicated read nodes](/guides/index-data/dedicated-read-nodes) for large workloads (millions of records or more, and moderate or high query rates).
This page shows you how to manage pod-based indexes.
For guidance on serverless indexes, see [Manage serverless indexes](/guides/manage-data/manage-indexes).
## Describe a pod-based index
Use the [`describe_index`](/reference/api/latest/control-plane/describe_index/) endpoint to get a complete description of a specific index:
```Python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
pc.describe_index(name="docs-example")
# Response:
# {'dimension': 1536,
# 'host': 'docs-example-4mkljsz.svc.aped-4627-b74a.pinecone.io',
# 'metric': 'cosine',
# 'name': 'docs-example',
# 'spec': {'pod': {'environment': 'us-east-1-aws',
# 'pod_type': 's1.x1',
# 'pods': 1,
# 'replicas': 1,
# 'shards': 1}},
# 'status': {'ready': True, 'state': 'Ready'}}
```
```JavaScript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' });
await pc.describeIndex('docs-example');
// Response:
// {
// "name": "docs-example",
// "dimension": 1536,
// "metric": "cosine",
// "host": "docs-example-4mkljsz.svc.aped-4627-b74a.pinecone.io",
// "deletionProtection": "disabled",
// "spec": {
// "pod": {
// "environment": "us-east-1-aws",
// "pod_type": "s1.x1",
// "pods": 1,
// "replicas": 1,
// "shards": 1
// }
// },
// "status": {
// "ready": true,
// "state": "Ready"
// }
// }
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.model.*;
public class DescribeIndexExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("YOURE_API_KEY").build();
IndexModel indexModel = pc.describeIndex("docs-example");
System.out.println(indexModel);
}
}
// Response:
// class IndexModel {
// name: docs-example
// dimension: 1536
// metric: cosine
// host: docs-example-4mkljsz.svc.aped-4627-b74a.pinecone.io
// deletionProtection: disabled
// spec: class IndexModelSpec {
// serverless: null
// pod: class PodSpec {
// cloud: aws
// region: us-east-1
// environment: us-east-1-aws,
// podType: s1.x1,
// pods: 1,
// replicas: 1,
// shards: 1
// }
// }
// status: class IndexModelStatus {
// ready: true
// state: Ready
// }
// }
```
```go Go theme={null}
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func prettifyStruct(obj interface{}) string {
bytes, _ := json.MarshalIndent(obj, "", " ")
return string(bytes)
}
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
idx, err := pc.DescribeIndex(ctx, "docs-example")
if err != nil {
log.Fatalf("Failed to describe index \"%v\": %v", idx.Name, err)
} else {
fmt.Printf("index: %v\n", prettifyStruct(idx))
}
}
// Response:
// index: {
// "name": "docs-example",
// "dimension": 1536,
// "host": "docs-example-4mkljsz.svc.aped-4627-b74a.pinecone.io",
// "metric": "cosine",
// "deletion_protection": "disabled",
// "spec": {
// "pod": {
// "environment": "us-east-1-aws",
// "pod_type": "s1.x1",
// "pods": 1,
// "replicas": 1,
// "shards": 1
// }
// },
// "status": {
// "ready": true,
// "state": "Ready"
// }
// }
```
```bash curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -i -X GET "https://api.pinecone.io/indexes/docs-example" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10"
# Response:
# {
# "name": "docs-example",
# "metric": "cosine",
# "dimension": 1536,
# "status": {
# "ready": true,
# "state": "Ready"
# },
# "host": "docs-example-4mkljsz.svc.aped-4627-b74a.pinecone.io",
# "spec": {
# "pod": {
# "environment": "us-east-1-aws",
# "pod_type": "s1.x1",
# "pods": 1,
# "replicas": 1,
# "shards": 1
# }
# }
# }
```
**Do not target an index by name in production.**
When you target an index by name for data operations such as `upsert` and `query`, the SDK gets the unique DNS host for the index using the `describe_index` operation. This is convenient for testing but should be avoided in production because `describe_index` uses a different API than data operations and therefore adds an additional network call and point of failure. Instead, you should get an index host once and cache it for reuse or specify the host directly.
## Delete a pod-based index
Use the [`delete_index`](/reference/api/latest/control-plane/delete_index) operation to delete a pod-based index and all of its associated resources.
You are billed for a pod-based index even when it is not in use.
```python Python theme={null}
# pip install "pinecone[grpc]"
from pinecone.grpc import PineconeGRPC as Pinecone, PodSpec
pc = Pinecone(api_key="YOUR_API_KEY")
pc.delete_index(name="docs-example")
```
```javascript JavaScript theme={null}
// npm install @pinecone-database/pinecone
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({
apiKey: 'YOUR_API_KEY'
});
await pc.deleteIndex('docs-example');
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
public class DeleteIndexExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
pc.deleteIndex("docs-example");
}
}
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
indexName := "docs-example"
err = pc.DeleteIndex(ctx, indexName)
if err != nil {
log.Fatalf("Failed to delete index: %v", err)
} else {
fmt.Println("Index \"%v\" deleted successfully", indexName)
}
}
```
```shell curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -i -X DELETE "https://api.pinecone.io/indexes/docs-example" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10"
```
If deletion protection is enabled on an index, requests to delete it will fail and return a `403 - FORBIDDEN` status with the following error:
```
Deletion protection is enabled for this index. Disable deletion protection before retrying.
```
Before you can delete such an index, you must first [disable deletion protection](/guides/manage-data/manage-indexes#configure-deletion-protection).
You can delete an index using the [Pinecone console](https://app.pinecone.io/organizations/-/projects/-/indexes). For the index you want to delete, click the three dots to the right of the index name, then click **Delete**.
## Selective metadata indexing
For pod-based indexes, Pinecone indexes all metadata fields by default. When metadata fields contains many unique values, pod-based indexes will consume significantly more memory, which can lead to performance issues, pod fullness, and a reduction in the number of possible vectors that fit per pod.
To avoid indexing high-cardinality metadata that is not needed for [filtering your queries](/guides/index-data/indexing-overview#metadata) and keep memory utilization low, specify which metadata fields to index using the `metadata_config` parameter.
Since high-cardinality metadata does not cause high memory utilization in serverless indexes, selective metadata indexing is not supported.
The value for the `metadata_config` parameter is a JSON object containing the names of the metadata fields to index.
```JSON JSON theme={null}
{
"indexed": [
"metadata-field-1",
"metadata-field-2",
"metadata-field-n"
]
}
```
**Example**
The following example creates a pod-based index that only indexes the `genre` metadata field. Queries against this index that filter for the `genre` metadata field may return results; queries that filter for other metadata fields behave as though those fields do not exist.
```Python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone, PodSpec
pc = Pinecone(api_key="YOUR_API_KEY")
pc.create_index(
name="docs-example",
dimension=1536,
metric="cosine",
spec=PodSpec(
environment="us-west1-gcp",
pod_type="p1.x1",
pods=1,
metadata_config = {
"indexed": ["genre"]
}
),
deletion_protection="disabled"
)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({
apiKey: 'YOUR_API_KEY'
});
await pc.createIndex({
name: 'docs-example',
dimension: 1536,
metric: 'cosine',
spec: {
pod: {
environment: 'us-west1-gcp',
podType: 'p1.x1',
pods: 1,
metadata_config: {
indexed: ["genre"]
}
}
},
deletionProtection: 'disabled',
});
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.model.IndexModel;
import org.openapitools.db_control.client.model.DeletionProtection;
public class CreateIndexExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
CreateIndexRequestSpecPodMetadataConfig podSpecMetadataConfig = new CreateIndexRequestSpecPodMetadataConfig();
List indexedItems = Arrays.asList("genre", "year");
podSpecMetadataConfig.setIndexed(indexedItems);
pc.createPodsIndex("docs-example", 1536, "us-west1-gcp",
"p1.x1", "cosine", podSpecMetadataConfig, DeletionProtection.DISABLED);
}
}
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
podIndexMetadata := &pinecone.PodSpecMetadataConfig{
Indexed: &[]string{"genre"},
}
indexName := "docs-example"
metric := pinecone.Dotproduct
deletionProtection := pinecone.DeletionProtectionDisabled
idx, err := pc.CreatePodIndex(ctx, &pinecone.CreatePodIndexRequest{
Name: indexName,
Metric: &metric,
Dimension: 1536,
Environment: "us-east1-gcp",
PodType: "p1.x1",
DeletionProtection: &deletionProtection,
})
if err != nil {
log.Fatalf("Failed to create pod-based index: %v", idx.Name)
} else {
fmt.Printf("Successfully created pod-based index: %v", idx.Name)
}
}
```
```bash curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -s https://api.pinecone.io/indexes \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"name": "docs-example",
"dimension": 1536,
"metric": "cosine",
"spec": {
"pod": {
"environment": "us-west1-gcp",
"pod_type": "p1.x1",
"pods": 1,
"metadata_config": {
"indexed": ["genre"]
}
}
},
"deletion_protection": "disabled"
}'
```
## Prevent index deletion
This feature requires [Pinecone API version](/reference/api/versioning) `2024-07`, [Python SDK](/reference/sdks/python/overview) v5.0.0, [Node.js SDK](/reference/sdks/node/overview) v3.0.0, [Java SDK](/reference/sdks/java/overview) v2.0.0, or [Go SDK](/reference/sdks/go/overview) v1.0.0 or later.
You can prevent an index and its data from accidental deleting when [creating a new index](/guides/index-data/create-an-index) or when [configuring an existing index](/guides/indexes/pods/manage-pod-based-indexes). In both cases, you set the `deletion_protection` parameter to `enabled`.
To enable deletion protection when creating a new index:
```python Python theme={null}
# pip install "pinecone[grpc]"
from pinecone.grpc import PineconeGRPC as Pinecone, PodSpec
pc = Pinecone(api_key="YOUR_API_KEY")
pc.create_index(
name="docs-example",
dimension=1536,
metric="cosine",
spec=PodSpec(
environment="us-west1-gcp",
pod_type="p1.x1",
pods=1
),
deletion_protection="enabled"
)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({
apiKey: 'YOUR_API_KEY'
});
await pc.createIndex({
name: 'docs-example',
dimension: 1536,
metric: 'cosine',
spec: {
pod: {
environment: 'us-west1-gcp',
podType: 'p1.x1',
pods: 1
}
},
deletionProtection: 'enabled',
});
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.model.IndexModel;
import org.openapitools.db_control.client.model.DeletionProtection;
public class CreateIndexExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
pc.createPodsIndex("docs-example", 1536, "us-west1-gcp",
"p1.x1", "cosine", DeletionProtection.ENABLED);
}
}
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
indexName := "docs-example"
metric := pinecone.Dotproduct
deletionProtection := pinecone.DeletionProtectionDisabled
idx, err := pc.CreatePodIndex(ctx, &pinecone.CreatePodIndexRequest{
Name: indexName,
Metric: &metric,
Dimension: 1536,
Environment: "us-east1-gcp",
PodType: "p1.x1",
DeletionProtection: &deletionProtection,
})
if err != nil {
log.Fatalf("Failed to create pod-based index: %v", idx.Name)
} else {
fmt.Printf("Successfully created pod-based index: %v", idx.Name)
}
}
```
```bash curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -s "https://api.pinecone.io/indexes" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"name": "docs-example",
"dimension": 1536,
"metric": "cosine",
"spec": {
"pod": {
"environment": "us-west1-gcp",
"pod_type": "p1.x1",
"pods": 1
}
},
"deletion_protection": "enabled"
}'
```
To enable deletion protection when configuring an existing index:
```python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
pc.configure_index(
name="docs-example",
deletion_protection="enabled"
)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const client = new Pinecone({ apiKey: 'YOUR_API_KEY' });
await client.configureIndex('docs-example', { deletionProtection: 'enabled' });
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.model.*;
public class ConfigureIndexExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
pc.configurePodsIndex("docs-example", DeletionProtection.ENABLED);
}
}
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
idx, err := pc.ConfigureIndex(ctx, "docs-example", pinecone.ConfigureIndexParams{DeletionProtection: "enabled"})
if err != nil {
log.Fatalf("Failed to configure index \"%v\": %v", idx.Name, err)
} else {
fmt.Printf("Successfully configured index \"%v\"", idx.Name)
}
}
```
```shell curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -s -X PATCH "https://api.pinecone.io/indexes/docs-example" \
-H "Content-Type: application/json" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"deletion_protection": "enabled"
}'
```
When deletion protection is enabled on an index, requests to delete the index fail and return a `403 - FORBIDDEN` status with the following error:
```
Deletion protection is enabled for this index. Disable deletion protection before retrying.
```
## Disable deletion protection
Before you can [delete an index](#delete-a-pod-based-index) with deletion protection enabled, you must first disable deletion protection as follows:
```python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
pc.configure_index(
name="docs-example",
deletion_protection="disabled"
)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const client = new Pinecone({ apiKey: 'YOUR_API_KEY' });
await client.configureIndex('docs-example', { deletionProtection: 'disabled' });
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.model.*;
public class ConfigureIndexExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
pc.configurePodsIndex("docs-example", DeletionProtection.DISABLED);
}
}
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
idx, err := pc.ConfigureIndex(ctx, "docs-example", pinecone.ConfigureIndexParams{DeletionProtection: "disabled"})
if err != nil {
log.Fatalf("Failed to configure index \"%v\": %v", idx.Name, err)
} else {
fmt.Printf("Successfully configured index \"%v\"", idx.Name)
}
}
```
```shell curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -s -X PATCH "https://api.pinecone.io/indexes/docs-example" \
-H "Content-Type: application/json" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"deletion_protection": "disabled"
}'
```
## Delete an entire namespace
In pod-based indexes, reads and writes share compute resources, so deleting an entire namespace with many records can increase the latency of read operations. In such cases, consider [deleting records in batches](#delete-records-in-batches).
## Delete records in batches
In pod-based indexes, reads and writes share compute resources, so deleting an entire namespace or a large number of records can increase the latency of read operations. To avoid this, delete records in batches of up to 1000, with a brief sleep between requests. Consider using smaller batches if the index has active read traffic.
```python Batch delete a namespace theme={null}
from pinecone import Pinecone
import numpy as np
import time
pc = Pinecone(api_key='API_KEY')
INDEX_NAME = 'INDEX_NAME'
NAMESPACE = 'NAMESPACE_NAME'
# Consider using smaller batches if you have a high RPS for read operations
BATCH = 1000
index = pc.Index(name=INDEX_NAME)
dimensions = index.describe_index_stats()['dimension']
# Create the query vector
query_vector = np.random.uniform(-1, 1, size=dimensions).tolist()
results = index.query(vector=query_vector, namespace=NAMESPACE, top_k=BATCH)
# Delete in batches until the query returns no results
while len(results['matches']) > 0:
ids = [i['id'] for i in results['matches']]
index.delete(ids=ids, namespace=NAMESPACE)
time.sleep(0.01)
results = index.query(vector=query_vector, namespace=NAMESPACE, top_k=BATCH)
```
```python Batch delete by metadata theme={null}
from pinecone import Pinecone
import numpy as np
import time
pc = Pinecone(api_key='API_KEY')
INDEX_NAME = 'INDEX_NAME'
NAMESPACE = 'NAMESPACE_NAME'
# Consider using smaller batches if you have a high RPS for read operations
BATCH = 1000
index = pc.Index(name=INDEX_NAME)
dimensions = index.describe_index_stats()['dimension']
METADATA_FILTER = {}
# Create the query vector with a filter
query_vector = np.random.uniform(-1, 1, size=dimensions).tolist()
results = index.query(vector=query_vector, namespace=NAMESPACE, filter=METADATA_FILTER, top_k=BATCH)
# Delete in batches until the query returns no results
while len(results['matches']) > 0:
ids = [i['id'] for i in results['matches']]
index.delete(ids=ids, namespace=NAMESPACE)
time.sleep(0.01)
results = index.query(vector=query_vector, namespace=NAMESPACE, filter=METADATA_FILTER, top_k=BATCH)
```
## Delete records by metadata
In pod-based indexes, if you are targeting a large number of records for deletion and the index has active read traffic, consider [deleting records in batches](#delete-records-in-batches).
To delete records from a namespace based on their metadata values, pass a [metadata filter expression](/guides/index-data/indexing-overview#metadata-filter-expressions) to the `delete` operation. This deletes all records in the namespace that match the filter expression.
For example, the following code deletes all records with a `genre` field set to `documentary` from namespace `example-namespace`:
```Python Python theme={null}
# pip install "pinecone[grpc]"
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
index = pc.Index(host="INDEX_HOST")
index.delete(
filter={
"genre": {"$eq": "documentary"}
},
namespace="example-namespace"
)
```
```JavaScript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({ apiKey: "YOUR_API_KEY" })
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
const index = pc.index("INDEX_NAME", "INDEX_HOST")
const ns = index.namespace('example-namespace')
await ns.deleteMany({
genre: { $eq: "documentary" },
});
```
```java Java theme={null}
import com.google.protobuf.Struct;
import com.google.protobuf.Value;
import io.pinecone.clients.Index;
import io.pinecone.configs.PineconeConfig;
import io.pinecone.configs.PineconeConnection;
import java.util.Arrays;
import java.util.List;
public class DeleteExample {
public static void main(String[] args) {
PineconeConfig config = new PineconeConfig("YOUR_API_KEY");
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
config.setHost("INDEX_HOST");
PineconeConnection connection = new PineconeConnection(config);
Index index = new Index(connection, "INDEX_NAME");
Struct filter = Struct.newBuilder()
.putFields("genre", Value.newBuilder()
.setStructValue(Struct.newBuilder()
.putFields("$eq", Value.newBuilder()
.setStringValue("documentary")
.build()))
.build())
.build();
index.deleteByFilter(filter, "example-namespace");
}
}
```
```go Go theme={null}
package main
import (
"context"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
idxConnection, err := pc.Index(pinecone.NewIndexConnParams{Host: "INDEX_HOST", Namespace: "example-namespace"})
if err != nil {
log.Fatalf("Failed to create IndexConnection for Host: %v", err)
}
metadataFilter := map[string]interface{}{
"genre": map[string]interface{}{
"$eq": "documentary",
},
}
filter, err := structpb.NewStruct(metadataFilter)
if err != nil {
log.Fatalf("Failed to create metadata filter: %v", err)
}
err = idxConnection.DeleteVectorsByFilter(ctx, filter)
if err != nil {
log.Fatalf("Failed to delete vector(s) with filter %+v: %v", filter, err)
}
}
```
```bash curl theme={null}
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
curl -i "https://$INDEX_HOST/vectors/delete" \
-H 'Api-Key: $PINECONE_API_KEY' \
-H 'Content-Type: application/json' \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"filter": {"genre": {"$eq": "documentary"}},
"namespace": "example-namespace"
}'
```
## Tag an index
When configuring an index, you can tag the index to help with index organization and management. For more details, see [Tag an index](/guides/manage-data/manage-indexes#configure-index-tags).
## Manage costs
### Set a project pod limit
To control costs, [project owners](/guides/projects/understanding-projects#project-roles) can [set the maximum total number of pods](/reference/api/database-limits#pods-per-project) allowed across all pod-based indexes in a project. The default pod limit is 5.
1. Go to [Settings > Projects](https://app.pinecone.io/organizations/-/settings/projects).
2. For the project you want to update, click the **ellipsis (...) menu > Configure**.
3. In the **Pod Limit** section, update the number of pods.
4. Click **Save Changes**.
```bash curl theme={null}
PINECONE_ACCESS_TOKEN="YOUR_ACCESS_TOKEN"
PROJECT_ID="YOUR_PROJECT_ID"
curl -X PATCH "https://api.pinecone.io/admin/projects/$PROJECT_ID" \
-H "accept: application/json" \
-H "Content-Type: application/json" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"max_pods": 5
}'
```
The example returns a response like the following:
```json theme={null}
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"name": "example-project",
"max_pods": 5,
"force_encryption_with_cmek": false,
"organization_id": "string",
"created_at": "2025-03-17T00:42:31.912Z"
}
```
### Back up inactive pod-based indexes
For each pod-based index, billing is determined by the per-minute price per pod and the number of pods the index uses, regardless of index activity. When a pod-based index is not in use, [back it up using collections](/guides/indexes/pods/back-up-a-pod-based-index) and delete the inactive index. When you're ready to use the vectors again, you can [create a new index from the collection](/guides/indexes/pods/create-a-pod-based-index#create-a-pod-index-from-a-collection). This new index can also use a different index type or size. Because it's relatively cheap to store collections, you can reduce costs by only running an index when it's in use.
### Choose the right index type and size
Pod sizes are designed for different applications, and some are more expensive than others. [Choose the appropriate pod type and size](/guides/indexes/pods/choose-a-pod-type-and-size), so you pay for the resources you need. For example, the `s1` pod type provides large storage capacity and lower overall costs with slightly higher query latencies than `p1` pods. By switching to a different pod type, you may be able to reduce costs while still getting the performance your application needs.
For pod-based indexes, project owners can [set limits for the total number of pods](/reference/api/database-limits#pods-per-project) across all indexes in the project. The default pod limit is 5.
## Monitor performance
Pinecone generates time-series performance metrics for each Pinecone index. You can monitor these metrics directly in the Pinecone console or with tools like Prometheus or Datadog.
### Use the Pinecone Console
To view performance metrics in the Pinecone console:
1. Open the [Pinecone console](https://app.pinecone.io/organizations/-/projects).
2. Select the project containing the index you want to monitor.
3. Go to **Database > Indexes**.
4. Select the index.
5. Go to the **Metrics** tab.
### Use Datadog
To monitor Pinecone with Datadog, use Datadog's [Pinecone integration](/integrations/datadog).
This feature is available on [Standard and Enterprise plans](https://www.pinecone.io/pricing/).
### Use Prometheus
This feature is available on [Standard and Enterprise plans](https://www.pinecone.io/pricing/). When using [Bring Your Own Cloud](/guides/production/bring-your-own-cloud), you must configure Prometheus monitoring within your VPC.
To monitor all pod-based indexes in a specific region of a project, insert the following snippet into the [`scrape_configs`](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#scrape_config) section of your `prometheus.yml` file and update it with values for your Prometheus integration:
```YAML theme={null}
scrape_configs:
- job_name: "pinecone-pod-metrics"
scheme: https
metrics_path: '/metrics'
authorization:
credentials: API_KEY
static_configs:
- targets: ["metrics.ENVIRONMENT.pinecone.io" ]
```
* Replace `API_KEY` with an API key for the project you want to monitor. If necessary, you can [create an new API key](/reference/api/authentication) in the Pinecone console.
* Replace `ENVIRONMENT` with the [environment](/guides/indexes/pods/understanding-pod-based-indexes#pod-environments) of the pod-based indexes you want to monitor.
For more configuration details, see the [Prometheus docs](https://prometheus.io/docs/prometheus/latest/configuration/configuration/).
#### Available metrics
The following metrics are available when you integrate Pinecone with Prometheus:
| Name | Type | Description |
| :----------------------------------- | :-------- | :-------------------------------------------------------------------------------- |
| `pinecone_vector_count` | gauge | The number of records per pod in the index. |
| `pinecone_request_count_total` | counter | The number of data plane calls made by clients. |
| `pinecone_request_error_count_total` | counter | The number of data plane calls made by clients that resulted in errors. |
| `pinecone_request_latency_seconds` | histogram | The distribution of server-side processing latency for pinecone data plane calls. |
| `pinecone_index_fullness` | gauge | The fullness of the index on a scale of 0 to 1. |
#### Metric labels
Each metric contains the following labels:
| Label | Description |
| :------------- | :--------------------------------------------------------------------------------------------------------------------------------------------- |
| `pid` | Process identifier. |
| `index_name` | Name of the index to which the metric applies. |
| `project_name` | Name of the project containing the index. |
| `request_type` | Type of request: `upsert`, `delete`, `fetch`, `query`, or `describe_index_stats`. This label is included only in `pinecone_request_*` metrics. |
#### Example queries
Return the average latency in seconds for all requests against the Pinecone index `docs-example`:
```shell theme={null}
avg by (request_type) (pinecone_request_latency_seconds{index_name="docs-example"})
```
Return the vector count for the Pinecone index `docs-example`:
```shell theme={null}
sum ((avg by (app) (pinecone_vector_count{index_name="docs-example"})))
```
Return the total number of requests against the Pinecone index `docs-example` over one minute:
```shell theme={null}
sum by (request_type)(increase(pinecone_request_count_total{index_name="docs-example"}[60s]))
```
Return the total number of upsert requests against the Pinecone index `docs-example` over one minute:
```shell theme={null}
sum by (request_type)(increase(pinecone_request_count_total{index_name="docs-example", request_type="upsert"}[60s]))
```
Return the total errors returned by the Pinecone index `docs-example` over one minute:
```shell theme={null}
sum by (request_type) (increase(pinecone_request_error_count{
index_name="docs-example"}[60s]))
```
Return the index fullness metric for the Pinecone index `docs-example`:
```
round(max (pinecone_index_fullness{index_name="docs-example"} * 100))
```
## Troubleshooting
### Index fullness errors
Serverless indexes automatically scale as needed.
However, pod-based indexes can run out of capacity. When that happens, upserting new records will fail with the following error:
```console console theme={null}
Index is full, cannot accept data.
```
### High-cardinality metadata and over-provisioning
This [Loom video walkthrough](https://www.loom.com/share/ce6f5dd0c3e14ba0b988fe32d96b703a?sid=48646dfe-c10c-4143-82c6-031fefe05a68) shows you how to manage two scenarios:
* The first scenario involves customers loading an index replete with high cardinality metadata. This can trigger a series of unforeseen challenges, and hence, it's vital to comprehend how to manage this situation effectively. This methodology can be applied whenever you need to change your metadata configuration.
* The second scenario that we will address involves customers who have over-provisioned the number of pods they need. More specifically, we will discuss the process of re-scaling an index in instances where the customer has previously scaled vertically and now desires to scale the index back down.
# Migrate a pod-based index to serverless
Source: https://docs.pinecone.io/guides/indexes/pods/migrate-a-pod-based-index-to-serverless
Migrate a Pinecone pod-based index to serverless for automatic scaling, better performance, and usage-based pricing with no minimum spend commitment.
This page shows you how to migrate a pod-based index to [serverless](/guides/get-started/database-architecture). The migration process is free; the standard costs of upserting records to a new serverless index are not applied.
In most cases, migrating to serverless reduces costs significantly. For read-heavy workloads with more than 1 query per second and for indexes with many records in a single namespace, consider building your serverless indexes on [dedicated read nodes](/guides/index-data/dedicated-read-nodes).
Before migrating, [contact Pinecone Support](/troubleshooting/contact-support) for help estimating and managing cost implications.
## Limitations
Migration is supported for pod-based indexes with less than 25 million records and 20,000 namespaces across all supported clouds (AWS, GCP, and Azure).
Also, serverless indexes do not support the following features. If you were using these features for your pod-based index, you will need to adapt your code. If you are blocked by these limitations, [contact Pinecone Support](/troubleshooting/contact-support).
* [Selective metadata indexing](/guides/indexes/pods/manage-pod-based-indexes#selective-metadata-indexing)
* Because high-cardinality metadata in serverless indexes does not cause high memory utilization, this operation is not relevant.
* [Filtering index statistics by metadata](/reference/api/latest/data-plane/describeindexstats)
## How it works
Migrating a pod-based index to serverless is a 2-step process:
After migration, you will have both a new serverless index and the original pod-based index. Once you've switched your workload to the serverless index, you can delete the pod-based index to avoid paying for unused resources.
## 1. Understand cost implications
In most cases, migrating to serverless reduces costs significantly. However, costs can increase for read-heavy workloads with more than 1 query per second and for indexes with many records in a single namespace.
Before migrating, consider [contacting Pinecone Support](/troubleshooting/contact-support) for help estimating and managing cost implications.
## 2. Prepare for migration
Migrating a pod-based index to serverless can take anywhere from a few minutes to several hours, depending on the size of the index. During that time, you can continue reading from the pod-based index. However, all [upserts](/guides/index-data/upsert-data), [updates](/guides/manage-data/update-data), and [deletes](/guides/manage-data/delete-data) to the pod-based index will not automatically be reflected in the new serverless index, so be sure to prepare in one of the following ways:
* **Pause write traffic:** If downtime is acceptable, pause traffic to the pod-based index before starting migration. After migration, you will start sending traffic to the serverless index.
* **Log your writes:** If you need to continue reading from the pod-based index during migration, send read traffic to the pod-based index, but log your writes to a temporary location outside of Pinecone (e.g., S3). After migration, you will replay the logged writes to the new serverless index and start sending all traffic to the serverless index.
## 3. Start migration
1. In the [Pinecone console](https://app.pinecone.io/), go to your pod-based index and click the **ellipsis (...) menu > Migrate to serverless**.
The dropdown will not display **Migrate to serverless** if the index has any of the listed [limitations](#limitations).
2. To save the legacy index and create a new serverless index now, follow the prompts.
Depending on the size of the index, migration can take anywhere from a few minutes to several hours. While migration is in progress, you'll see the yellow **Initializing** status:
When the new serverless index is ready, the status will change to green:
1. Use the [`create_collection`](/reference/api/latest/control-plane/create_collection) operation to create a backup of your pod-based index:
```javascript JavaScript theme={null}
// Requires Node.js SDK v6.1.2 or later
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({
apiKey: 'YOUR_API_KEY'
});
await pc.createCollection({
name: "pod-collection",
source: "pod-index"
});
```
```go Go theme={null}
// Requires Go SDK v4.1.2 or later
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
collection, err := pc.CreateCollection(ctx, &pinecone.CreateCollectionRequest{
Name: "pod-collection",
Source: "pod-index",
})
if err != nil {
log.Fatalf("Failed to create collection: %v", err)
} else {
fmt.Printf("Successfully created collection: %v", collection.Name)
}
}
```
```shell curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -s POST "https://api.pinecone.io/collections" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"name": "pod-collection",
"source": "pod-index"
}'
```
2. Use the [`create_index`](/reference/api/latest/control-plane/create_index) operation to create a new serverless index from the collection:
* Use API verison `2025-04` or later. Creating a serverless index from a collection is not supported in earlier versions.
* Set `dimension` to the same dimension as the pod-based index. Changing the dimension is not supported.
* Set `cloud` to the cloud where the pod-based index is hosted. Migrating to a different cloud is not supported.
* Set `source_collection` to the name of the collection you created in step 1.
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({
apiKey: 'YOUR_API_KEY'
});
await pc.createIndex({
name: 'serverless-index',
vectorType: 'dense',
dimension: 1536,
metric: 'cosine',
spec: {
serverless: {
cloud: 'aws',
region: 'us-east-1',
sourceCollection: 'pod-collection'
}
}
});
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
idx, err := pc.CreateServerlessIndex(ctx, &pinecone.CreateServerlessIndexRequest{
Name: "serverless-index",
VectorType: "dense",
Dimension: 1536,
Metric: pinecone.Cosine,
Cloud: pinecone.Aws,
Region: "us-east-1",
SourceCollection: "pod-collection",
})
if err != nil {
log.Fatalf("Failed to create serverless index: %v", err)
} else {
fmt.Printf("Successfully created serverless index: %v", idx.Name)
}
}
```
```shell curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -s "https://api.pinecone.io/indexes" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"name": "serverless-index",
"vector_type": "dense",
"dimension": 1536,
"metric": "cosine",
"spec": {
"serverless": {
"cloud": "aws",
"region": "us-east-1",
"source_collection": "pod-collection"
}
}
}'
```
## 4. Update SDKs
If you are using an older version of the Python, Node.js, Java, or Go SDK, you must update the SDK to work with serverless indexes.
1. Check your SDK version:
```shell Python theme={null}
pip show pinecone
```
```shell JavaScript theme={null}
npm list | grep @pinecone-database/pinecone
```
```shell Java theme={null}
# Check your dependency file or classpath
```
```shell Go theme={null}
go list -u -m all | grep go-pinecone
```
2. If your SDK version is less than 3.0.0 for [Python](https://github.com/pinecone-io/pinecone-python-client), 2.0.0 for [Node.js](https://sdk.pinecone.io/typescript/), 1.0.0 for [Java](https://github.com/pinecone-io/pinecone-java-client), or 1.0.0 for [Go](https://github.com/pinecone-io/go-pinecone), upgrade the SDK as follows:
```Python Python theme={null}
pip install "pinecone[grpc]" --upgrade
```
```JavaScript JavaScript theme={null}
npm install @pinecone-database/pinecone@latest
```
```shell Java theme={null}
# Maven
io.pineconepinecone-client5.0.0
# Gradle
implementation "io.pinecone:pinecone-client:5.0.0"
```
```go Go theme={null}
go get -u github.com/pinecone-io/go-pinecone/v4/pinecone@latest
```
## 5. Adapt existing code
You must make some minor code changes to work with serverless indexes.
Serverless indexes do not support some features, as outlined in [Limitations](#limitations). If you were relying on these features for your pod-based index, you’ll need to adapt your code.
1. Change how you import the Pinecone library and authenticate and initialize the client:
```Python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
from pinecone import ServerlessSpec, PodSpec
# ServerlessSpec and PodSpec are required only when
# creating serverless and pod-based indexes.
pc = Pinecone(api_key="YOUR_API_KEY")
```
```JavaScript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' });
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.model.*;
public class InitializeClientExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
}
}
```
```go Go theme={null}
package main
import (
"context"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
}
```
2. [Listing indexes](/guides/manage-data/manage-indexes) now fetches a complete description of each index. If you were relying on the output of this operation, you'll need to adapt your code.
```Python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
index_list = pc.list_indexes()
print(index_list)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' })
const indexList = await pc.listIndexes();
console.log(indexList);
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.model.*;
public class ListIndexesExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
IndexList indexList = pc.listIndexes();
System.out.println(indexList);
}
}
```
```go Go theme={null}
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func prettifyStruct(obj interface{}) string {
bytes, _ := json.MarshalIndent(obj, "", " ")
return string(bytes)
}
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
idxs, err := pc.ListIndexes(ctx)
if err != nil {
log.Fatalf("Failed to list indexes: %v", err)
} else {
for _, index := range idxs {
fmt.Printf("index: %v\n", prettifyStruct(index))
}
}
}
```
```shell curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -i -X GET "https://api.pinecone.io/indexes" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10"
```
The `list_indexes` operation now returns a response like the following:
```python Python theme={null}
[{
"name": "docs-example-sparse",
"metric": "dotproduct",
"host": "docs-example-sparse-govk0nt.svc.aped-4627-b74a.pinecone.io",
"spec": {
"serverless": {
"cloud": "aws",
"region": "us-east-1"
}
},
"status": {
"ready": true,
"state": "Ready"
},
"vector_type": "sparse",
"dimension": null,
"deletion_protection": "disabled",
"tags": {
"environment": "development"
}
}, {
"name": "docs-example-dense",
"metric": "cosine",
"host": "docs-example-dense-govk0nt.svc.aped-4627-b74a.pinecone.io",
"spec": {
"serverless": {
"cloud": "aws",
"region": "us-east-1"
}
},
"status": {
"ready": true,
"state": "Ready"
},
"vector_type": "dense",
"dimension": 1536,
"deletion_protection": "disabled",
"tags": {
"environment": "development"
}
}]
```
```javascript JavaScript theme={null}
{
indexes: [
{
name: 'docs-example-sparse',
dimension: undefined,
metric: 'dotproduct',
host: 'docs-example-sparse-govk0nt.svc.aped-4627-b74a.pinecone.io',
deletionProtection: 'disabled',
tags: { environment: 'development', example: 'tag' },
embed: undefined,
spec: { pod: undefined, serverless: { cloud: 'aws', region: 'us-east-1' } },
status: { ready: true, state: 'Ready' },
vectorType: 'sparse'
},
{
name: 'docs-example-dense',
dimension: 1536,
metric: 'cosine',
host: 'docs-example-dense-govk0nt.svc.aped-4627-b74a.pinecone.io',
deletionProtection: 'disabled',
tags: { environment: 'development', example: 'tag' },
embed: undefined,
spec: { pod: undefined, serverless: { cloud: 'aws', region: 'us-east-1' } },
status: { ready: true, state: 'Ready' },
vectorType: 'dense'
}
]
}
```
```java Java theme={null}
class IndexList {
indexes: [class IndexModel {
name: docs-example-sparse
dimension: null
metric: dotproduct
host: docs-example-sparse-govk0nt.svc.aped-4627-b74a.pinecone.io
deletionProtection: disabled
tags: {environment=development}
embed: null
spec: class IndexModelSpec {
pod: null
serverless: class ServerlessSpec {
cloud: aws
region: us-east-1
additionalProperties: null
}
additionalProperties: null
}
status: class IndexModelStatus {
ready: true
state: Ready
additionalProperties: null
}
vectorType: sparse
additionalProperties: null
}, class IndexModel {
name: docs-example-dense
dimension: 1536
metric: cosine
host: docs-example-dense-govk0nt.svc.aped-4627-b74a.pinecone.io
deletionProtection: disabled
tags: {environment=development}
embed: null
spec: class IndexModelSpec {
pod: null
serverless: class ServerlessSpec {
cloud: aws
region: us-east-1
additionalProperties: null
}
additionalProperties: null
}
status: class IndexModelStatus {
ready: true
state: Ready
additionalProperties: null
}
vectorType: dense
additionalProperties: null
}]
additionalProperties: null
}
```
```go Go theme={null}
index: {
"name": "docs-example-sparse",
"host": "docs-example-sparse-govk0nt.svc.aped-4627-b74a.pinecone.io",
"metric": "dotproduct",
"vector_type": "sparse",
"deletion_protection": "disabled",
"dimension": null,
"spec": {
"serverless": {
"cloud": "aws",
"region": "us-east-1"
}
},
"status": {
"ready": true,
"state": "Ready"
},
"tags": {
"environment": "development"
}
}
index: {
"name": "docs-example-dense",
"host": "docs-example-dense-govk0nt.svc.aped-4627-b74a.pinecone.io",
"metric": "cosine",
"vector_type": "dense",
"deletion_protection": "disabled",
"dimension": 1536,
"spec": {
"serverless": {
"cloud": "aws",
"region": "us-east-1"
}
},
"status": {
"ready": true,
"state": "Ready"
},
"tags": {
"environment": "development"
}
}
```
```json curl theme={null}
{
"indexes": [
{
"name": "docs-example-sparse",
"vector_type": "sparse",
"metric": "dotproduct",
"dimension": null,
"status": {
"ready": true,
"state": "Ready"
},
"host": "docs-example-sparse-govk0nt.svc.aped-4627-b74a.pinecone.io",
"spec": {
"serverless": {
"region": "us-east-1",
"cloud": "aws"
}
},
"deletion_protection": "disabled",
"tags": {
"environment": "development"
}
},
{
"name": "docs-example-dense",
"vector_type": "dense",
"metric": "cosine",
"dimension": 1536,
"status": {
"ready": true,
"state": "Ready"
},
"host": "docs-example-dense-govk0nt.svc.aped-4627-b74a.pinecone.io",
"spec": {
"serverless": {
"region": "us-east-1",
"cloud": "aws"
}
},
"deletion_protection": "disabled",
"tags": {
"environment": "development"
}
}
]
}
```
3. [Describing an index](/guides/manage-data/manage-indexes) now returns a description of an index in a different format. It also returns the index host needed to run data plane operations against the index. If you were relying on the output of this operation, you'll need to adapt your code.
```Python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
pc.describe_index(name="docs-example")
```
```JavaScript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' });
await pc.describeIndex('docs-example');
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.model.*;
public class DescribeIndexExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("YOURE_API_KEY").build();
IndexModel indexModel = pc.describeIndex("docs-example");
System.out.println(indexModel);
}
}
```
```go Go theme={null}
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func prettifyStruct(obj interface{}) string {
bytes, _ := json.MarshalIndent(obj, "", " ")
return string(bytes)
}
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
idx, err := pc.DescribeIndex(ctx, "docs-example")
if err != nil {
log.Fatalf("Failed to describe index \"%v\": %v", idx.Name, err)
} else {
fmt.Printf("index: %v\n", prettifyStruct(idx))
}
}
```
```bash curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -i -X GET "https://api.pinecone.io/indexes/docs-example" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10"
```
## 6. Use your new index
When you're ready to cutover to your new serverless index:
1. Your new serverless index has a different name and unique endpoint than your pod-based index. Update your code to target the new serverless index:
```Python Python theme={null}
index = pc.Index("YOUR_SERVERLESS_INDEX_NAME")
```
```JavaScript JavaScript theme={null}
const index = pc.index("YOUR_SERVERLESS_INDEX_NAME");
```
```java Java theme={null}
import io.pinecone.clients.Index;
import io.pinecone.clients.Pinecone;
public class TargetIndexExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
Index index = pc.getIndexConnection("YOUR_SERVERLESS_INDEX_NAME");
```
```go Go theme={null}
package main
import (
"context"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
idx, err := pc.DescribeIndex(ctx, "YOUR_SERVERLESS_INDEX_NAME")
if err != nil {
log.Fatalf("Failed to describe index \"%v\": %v", idx.Name, err)
}
idxConnection, err := pc.Index(pinecone.NewIndexConnParams{Host: idx.Host, Namespace: "example-namespace"})
if err != nil {
log.Fatalf("Failed to create IndexConnection for Host %v: %v", idx.Host, err)
}
}
```
```bash curl theme={null}
# When using the API directly, you need the unique endpoint for your new serverless index.
# See https://docs.pinecone.io/guides/manage-data/target-an-index for details.
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
curl -X POST "https://$INDEX_HOST/describe_index_stats" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10"
```
2. Reinitialize your clients.
3. If you logged writes to the pod-based index during migration, replay the logged writes to your serverless index.
4. [Delete the pod-based index](/guides/manage-data/manage-indexes#delete-an-index) to avoid paying for unused resources.
It is not possible to save a serverless index as a collection, so if you want to retain the option to recreate your pod-based index, be sure to keep the collection you created earlier.
## See also
* [Limits](/reference/api/database-limits)
* [Serverless architecture](/guides/get-started/database-architecture)
* [Understanding serverless cost](/guides/manage-cost/understanding-cost)
# Restore a pod-based index
Source: https://docs.pinecone.io/guides/indexes/pods/restore-a-pod-based-index
Legacy guide for restoring Pinecone pod-based indexes from collections. Pod indexes are no longer available to new customers as of August 2025.
Customers who sign up for a Standard or Enterprise plan on or after August 18, 2025 cannot create pod-based indexes. Instead, create [serverless indexes](/guides/index-data/create-an-index), and consider using [dedicated read nodes](/guides/index-data/dedicated-read-nodes) for large workloads (millions of records or more, and moderate or high query rates).
You can restore a pod-based index by creating a new index from a [collection](/guides/indexes/pods/understanding-collections).
## Create a pod-based index from a collection
To create a pod-based index from a [collection](/guides/manage-data/back-up-an-index#pod-based-index-backups-using-collections), use the [`create_index`](/reference/api/latest/control-plane/create_index) endpoint and provide a [`source_collection`](/reference/api/latest/control-plane/create_index#!path=source%5Fcollection\&t=request) parameter containing the name of the collection from which you wish to create an index. The new index can differ from the original source index: the new index can have a different name, number of pods, or pod type. The new index is queryable and writable.
```Python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone, PodSpec
pc = Pinecone(api_key="YOUR_API_KEY")
pc.create_index(
name="docs-example",
dimension=128,
metric="cosine",
spec=PodSpec(
environment="us-west-1-gcp",
pod_type="p1.x1",
pods=1,
source_collection="example-collection"
)
)
```
```JavaScript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({
apiKey: 'YOUR_API_KEY'
});
await pc.createIndex({
name: 'docs-example',
dimension: 128,
metric: 'cosine',
spec: {
pod: {
environment: 'us-west-1-gcp',
podType: 'p1.x1',
pods: 1,
sourceCollection: 'example-collection'
}
}
});
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.model.IndexModel;
import org.openapitools.db_control.client.model.DeletionProtection;
public class CreateIndexFromCollectionExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
pc.createPodsIndex("docs-example", 1536, "us-west1-gcp",
"p1.x1", "cosine", "example-collection", DeletionProtection.DISABLED);
}
}
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
indexName := "docs-example"
metric := pinecone.Dotproduct
deletionProtection := pinecone.DeletionProtectionDisabled
idx, err := pc.CreatePodIndex(ctx, &pinecone.CreatePodIndexRequest{
Name: indexName,
Metric: &metric,
Dimension: 1536,
Environment: "us-east1-gcp",
PodType: "p1.x1",
SourceCollection: "example-collection",
DeletionProtection: &deletionProtection,
})
if err != nil {
log.Fatalf("Failed to create pod-based index: %v", idx.Name)
} else {
fmt.Printf("Successfully created pod-based index: %v", idx.Name)
}
}
```
```bash curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -s "https://api.pinecone.io/indexes" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"name": "docs-example",
"dimension": 128,
"metric": "cosine",
"spec": {
"pod": {
"environment": "us-west-1-gcp",
"pod_type": "p1.x1",
"pods": 1,
"source_collection": "example-collection"
}
}
}'
```
# Scale pod-based indexes
Source: https://docs.pinecone.io/guides/indexes/pods/scale-pod-based-indexes
Scale Pinecone pod-based indexes by adding pods or replicas. Legacy guide: pod indexes are unavailable to new customers; serverless scales automatically.
Customers who sign up for a Standard or Enterprise plan on or after August 18, 2025 cannot create pod-based indexes. Instead, create [serverless indexes](/guides/index-data/create-an-index), and consider using [dedicated read nodes](/guides/index-data/dedicated-read-nodes) for large workloads (millions of records or more, and moderate or high query rates).
While your index can still serve queries, new upserts may fail as the capacity becomes exhausted. If you need to scale your environment to accommodate more vectors, you can modify your existing index and scale it vertically or create a new index and scale horizontally.
This page explains how you can scale your [pod-based indexes](/guides/index-data/indexing-overview#pod-based-indexes) horizontally and vertically.
## Vertical vs. horizontal scaling
If you need to scale your environment to accommodate more vectors, you can modify your existing index to scale it vertically or create a new index and scale horizontally. This article will describe both methods and how to scale your index effectively.
## Vertical scaling
[Vertical scaling](https://www.pinecone.io/learn/testing-p2-collections-scaling/#vertical-scaling-on-p1-and-s1) is fast and involves no downtime. This is a good choice when you can't pause upserts and must continue serving traffic. It also allows you to double your capacity instantly. However, there are some factors to consider.
### Increase pod size
The default [pod size](/guides/index-data/indexing-overview#pod-size-and-performance) is `x1`. You can increase the size to `x2`, `x4`, or `x8`. Moving up to the next size effectively doubles the capacity of the index. If you need to scale by smaller increments, then consider horizontal scaling.
Increasing the pod size of your index does not result in downtime. Reads and writes continue uninterrupted during the scaling process, which completes in about 10 minutes. You cannot reduce the pod size of your indexes.
The number of base pods you specify when you initially create the index is static and cannot be changed. For example, if you start with 10 pods of `p1.x1` and vertically scale to `p1.x2`, this equates to 20 pods worth of usage. Pod types (performance versus storage pods) also cannot be changed with vertical scaling. If you want to change your pod type while scaling, then horizontal scaling is the better option.
#### When to increase pod size
If your index is at around 90% fullness, we recommend increasing its size. This helps ensure optimal performance and prevents upserts from failing due to capacity constraints.
#### How to increase pod size
You can increase the pod size in the Pinecone console or using the API.
1. Open the [Pinecone console](https://app.pinecone.io/organizations/-/projects).
2. Select the project containing the index you want to configure.
3. Go to **Database > Indexes**.
4. Select the index.
5. Click the **...** button.
6. Select **Configure**.
7. In the dropdown, choose the pod size to use.
8. Click **Confirm**.
Use the [`configure_index`](/reference/api/latest/control-plane/configure_index) operation and append the new size to the `pod_type` parameter, separated by a period (.).
**Example**
The following example assumes that `docs-example` has size `x1` and increases the size to `x2`.
```Python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
pc.configure_index("docs-example", pod_type="s1.x2")
```
```JavaScript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pinecone = new Pinecone({
apiKey: 'YOUR_API_KEY'
});
await pc.configureIndex('docs-example', {
spec: {
pod: {
podType: 's1.x2',
},
},
});
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
public class ConfigureIndexExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("PINECONE_API_KEY").build();
pc.configurePodsIndex("docs-example", "s1.x2");
}
}
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
idx, err := pc.ConfigureIndex(ctx, "docs-example", pinecone.ConfigureIndexParams{PodType: "s1.x2"})
if err != nil {
log.Fatalf("Failed to configure index \"%v\": %v", idx.Name, err)
} else {
fmt.Printf("Successfully configured index \"%v\"", idx.Name)
}
}
```
```bash curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -s -X PATCH "https://api.pinecone.io/indexes/docs-example-curl" \
-H "Content-Type: application/json" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"pod_type": "s1.x2"
}'
```
The size change can take up to 15 minutes to complete.
### Decrease pod size
After creating an index, you cannot vertically downscale the index/pod size. Instead, you must [create a collection](/guides/indexes/pods/back-up-a-pod-based-index) and then [create a new index from your collection](/guides/indexes/pods/restore-a-pod-based-index) and specify your desired pod size.
### Check the status of a pod size change
To check the status of a pod size change, use the [`describe_index`](/reference/api/latest/control-plane/describe_index/) endpoint. The `status` field in the results contains the key-value pair `"state":"ScalingUp"` or `"state":"ScalingDown"` during the resizing process and the key-value pair `"state":"Ready"` after the process is complete.
The index fullness metric provided by [`describe_index_stats`](/reference/api/latest/data-plane/describeindexstats) may be inaccurate until the resizing process is complete.
**Example**
The following example uses `describe_index` to get the index status of the index `docs-example`. The `status` field contains the key-value pair `"state":"ScalingUp"`, indicating that the resizing process is still ongoing.
```Python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
pc.describe_index(name="docs-example")
```
```JavaScript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({
apiKey: 'YOUR_API_KEY'
});
await pc.describeIndex({
name: "docs-example",
});
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.model.*;
public class DescribeIndexExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
IndexModel indexModel = pc.describeIndex("docs-example");
}
}
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
idx, err := pc.DescribeIndex(ctx, "docs-example")
if err != nil {
log.Fatalf("Failed to describe index %v: %v", idx.Name, err)
} else {
fmt.Printf("Successfully found index: %v", idx.Name)
}
}
```
```bash curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -s -X GET "https://api.pinecone.io/indexes/docs-example-curl" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10"
```
## Horizontal scaling
There are two approaches to horizontal scaling in Pinecone: adding pods and adding replicas. Adding pods increases all resources but requires a pause in upserts; adding replicas only increases throughput and requires no pause in upserts.
### Add pods
Adding additional pods to a running index is not supported directly. However, you can increase the number of pods by using our [collections](/guides/indexes/pods/understanding-collections) feature to create a new index with more pods.
A collection is an immutable snapshot of your index in time: a collection stores the data but not the original index configuration. When you [create an index from a collection](/guides/indexes/pods/create-a-pod-based-index#create-a-pod-index-from-a-collection), you define the new index configuration. This allows you to scale the base pod count horizontally without scaling vertically.
The main advantage of this approach is that you can scale incrementally instead of doubling capacity as with vertical scaling. Also, you can redefine pod types if you are experimenting or if you need to use a different pod type, such as performance-optimized pods or storage-optimized pods. Another advantage of this method is that you can change your [metadata configuration](/guides/indexes/pods/manage-pod-based-indexes#selective-metadata-indexing) to redefine metadata fields as indexed or stored-only. This is important when tuning your index for the best throughput.
Here are the general steps to make a copy of your index and create a new index while changing the pod type, pod count, metadata configuration, replicas, and all typical parameters when creating a new collection:
1. Pause upserts.
2. Create a collection from the current index.
3. Create an index from the collection with new parameters.
4. Continue upserts to the newly created index. Note: the URL has likely changed.
5. Delete the old index if desired.
For detailed steps on creating the collection, see [backup indexes](/guides/manage-data/back-up-an-index#create-a-backup-using-a-collection). For steps on creating an index from a collection, see [Create an index from a collection](/guides/indexes/pods/create-a-pod-based-index#create-a-pod-index-from-a-collection).
### Add replicas
Each replica duplicates the resources and data in an index. This means that adding additional replicas increases the throughput of the index but not its capacity. However, adding replicas does not require downtime.
Throughput in terms of queries per second (QPS) scales linearly with the number of replicas per index.
#### When to add replicas
There are two primary scenarios where adding replicas is beneficial:
**Increase QPS**: The primary reason to add replicas is to increase your index's queries per second (QPS). Each new replica adds another pod for reading from your index and, generally speaking, will increase your QPS by an equal amount as a single pod. For example, if you consistently get 25 QPS for a single pod, each replica will result in 25 more QPS.
If you don't see an increase in QPS after adding replicas, add multiprocessing to your application to ensure you are running parallel operations. You can use the [Pinecone gRPC SDK](/guides/index-data/upsert-data#grpc-python-sdk), or your multiprocessing library of choice.
**Provide data redundancy**: When you add a replica to your index, the Pinecone controller will choose a zone in the same region that does not currently have a replica, up to a maximum of three zones (your fourth and subsequent replicas will be hosted in zones with existing replicas). If your application requires multizone redundancy, this is our recommended approach to achieve that.
#### How to add replicas
To add replicas, use the `configure_index` endpoint to increase the number of replicas for your index:
```Python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
pc.configure_index("docs-example", replicas=4)
```
```JavaScript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({
apiKey: 'YOUR_API_KEY'
});
await pc.configureIndex('docs-example', {
spec: {
pod: {
replicas: 4,
},
},
});
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
public class ConfigureIndexExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("PINECONE_API_KEY").build();
pc.configurePodsIndex("docs-example", 4, DeletionProtection.DISABLED);
}
}
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
idx, err := pc.ConfigureIndex(ctx, "docs-example", pinecone.ConfigureIndexParams{Replicas: 4})
if err != nil {
log.Fatalf("Failed to configure index \"%v\": %v", idx.Name, err)
} else {
fmt.Printf("Successfully configured index \"%v\"", idx.Name)
}
}
```
```bash curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -s -X PATCH "https://api.pinecone.io/indexes/docs-example-curl" \
-H "Content-Type: application/json" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"replicas": 4
}'
```
## Next steps
* See our learning center for more information on [vertical scaling](https://www.pinecone.io/learn/testing-p2-collections-scaling/#vertical-scaling-on-p1-and-s1).
* Learn more about [collections](/guides/indexes/pods/understanding-collections).
# Understanding collections
Source: https://docs.pinecone.io/guides/indexes/pods/understanding-collections
Legacy documentation for Pinecone collections, a pod-only feature for creating static index snapshots. Collections are not available for serverless indexes.
Customers who sign up for a Standard or Enterprise plan on or after August 18, 2025 cannot create pod-based indexes. Instead, create [serverless indexes](/guides/index-data/create-an-index), and consider using [dedicated read nodes](/guides/index-data/dedicated-read-nodes) for large workloads (millions of records or more, and moderate or high query rates).
A collection is a static copy of a pod-based index that only consumes storage. It is a non-queryable representation of a set of records. You can [create a collection](/guides/indexes/pods/back-up-a-pod-based-index) of a pod-based index, and you can [create a new pod-based index from a collection](/guides/manage-data/restore-an-index). This allows you to restore the index with the same or different configurations.
Once a collection is created, it cannot be moved to a different project.
## Use cases
Creating a collection is useful when performing tasks like the following:
* Protecting an index from manual or system failures.
* Temporarily shutting down an index.
* Copying the data from one index into a different index.
* Making a backup of your index.
* Experimenting with different index configurations.
## Performance
Collections operations perform differently, depending on the pod type of the index:
* Creating a `p1` or `s1` index from a collection takes approximately 10 minutes.
* Creating a `p2` index from a collection can take several hours when the number of vectors is on the order of 1,000,000.
## Limitations
Collection limitations are as follows:
* You can only perform operations on collections in the current Pinecone project.
## Pricing
See [Pricing](https://www.pinecone.io/pricing/) for up-to-date pricing information.
# Understanding pod-based indexes
Source: https://docs.pinecone.io/guides/indexes/pods/understanding-pod-based-indexes
Understand Pinecone pod-based indexes, including pod types and sizing. Legacy: pod indexes are unavailable to new customers; use serverless for new projects.
Customers who sign up for a Standard or Enterprise plan on or after August 18, 2025 cannot create pod-based indexes. Instead, create [serverless indexes](/guides/index-data/create-an-index), and consider using [dedicated read nodes](/guides/index-data/dedicated-read-nodes) for large workloads (millions of records or more, and moderate or high query rates).
With pod-based indexes, you choose one or more pre-configured units of hardware (pods). Depending on the pod type, pod size, and number of pods used, you get different amounts of storage and higher or lower latency and throughput. Be sure to [choose an appropriate pod type and size](/guides/indexes/pods/choose-a-pod-type-and-size) for your dataset and workload.
## Pod types
Different pod types are priced differently. See [Understanding cost](/guides/manage-cost/understanding-cost) for more details.
Once a pod-based index is created, you cannot change its pod type. However, you can create a collection from an index and then [create a new index with a different pod type](/guides/indexes/pods/create-a-pod-based-index#create-a-pod-index-from-a-collection) from the collection.
### s1 pods
These storage-optimized pods provide large storage capacity and lower overall costs with slightly higher query latencies than p1 pods. They are ideal for very large indexes with moderate or relaxed latency requirements.
Each s1 pod has enough capacity for around 5M vectors of 768 dimensions.
### p1 pods
These performance-optimized pods provide very low query latencies, but hold fewer vectors per pod than s1 pods. They are ideal for applications with low latency requirements (\<100ms).
Each p1 pod has enough capacity for around 1M vectors of 768 dimensions.
### p2 pods
The p2 pod type provides greater query throughput with lower latency. For vectors with fewer than 128 dimension and queries where `topK` is less than 50, p2 pods support up to 200 QPS per replica and return queries in less than 10ms. This means that query throughput and latency are better than s1 and p1.
Each p2 pod has enough capacity for around 1M vectors of 768 dimensions. However, capacity may vary with dimensionality.
The data ingestion rate for p2 pods is significantly slower than for p1 pods; this rate decreases as the number of dimensions increases. For example, a p2 pod containing vectors with 128 dimensions can upsert up to 300 updates per second; a p2 pod containing vectors with 768 dimensions or more supports upsert of 50 updates per second. Because query latency and throughput for p2 pods vary from p1 pods, test p2 pod performance with your dataset.
The p2 pod type does not support sparse vector values.
## Pod size and performance
Each pod type supports four pod sizes: `x1`, `x2`, `x4`, and `x8`. Your index storage and compute capacity doubles for each size step. The default pod size is `x1`. You can increase the size of a pod after index creation.
To learn about changing the pod size of an index, see [Configure an index](/guides/indexes/pods/scale-pod-based-indexes#increase-pod-size).
## Pod environments
When creating a pod-based index, you must choose the cloud environment where you want the index to be hosted. The project environment can affect your [pricing](https://pinecone.io/pricing). The following table lists the available cloud regions and the corresponding values of the `environment` parameter for the [`create_index`](/guides/index-data/create-an-index#create-a-pod-based-index) endpoint:
| Cloud | Region | Environment |
| ----- | ---------------------------- | ----------------------------- |
| GCP | us-west-1 (N. California) | `us-west1-gcp` |
| GCP | us-central-1 (Iowa) | `us-central1-gcp` |
| GCP | us-west-4 (Las Vegas) | `us-west4-gcp` |
| GCP | us-east-4 (Virginia) | `us-east4-gcp` |
| GCP | northamerica-northeast-1 | `northamerica-northeast1-gcp` |
| GCP | asia-northeast-1 (Japan) | `asia-northeast1-gcp` |
| GCP | asia-southeast-1 (Singapore) | `asia-southeast1-gcp` |
| GCP | us-east-1 (South Carolina) | `us-east1-gcp` |
| GCP | eu-west-1 (Belgium) | `eu-west1-gcp` |
| GCP | eu-west-4 (Netherlands) | `eu-west4-gcp` |
| AWS | us-east-1 (Virginia) | `us-east-1-aws` |
| Azure | eastus (Virginia) | `eastus-azure` |
[Contact us](http://www.pinecone.io/contact/) if you need a dedicated deployment in other regions.
The environment cannot be changed after the index is created.
## Pod costs
For each pod-based index, billing is determined by the per-minute price per pod and the number of pods the index uses, regardless of index activity. The per-minute price varies by pod type, pod size, account plan, and cloud region. For the latest pod-based index pricing rates, see [Pricing](https://www.pinecone.io/pricing/pods).
Total cost depends on a combination of factors:
* **Pod type.** Each pod type has different per-minute pricing.
* **Number of pods.** This includes replicas, which duplicate pods.
* **Pod size.** Larger pod sizes have proportionally higher costs per minute.
* **Total pod-minutes.** This includes the total time each pod is running, starting at pod creation and rounded up to 15-minute increments.
* **Cloud provider.** The cost per pod-type and pod-minute varies depending on the cloud provider you choose for your project.
* **Collection storage.** Collections incur costs per GB of data per minute in storage, rounded up to 15-minute increments.
* **Plan.** The free plan incurs no costs; the Standard or Enterprise plans incur different costs per pod-type, pod-minute, cloud provider, and collection storage.
The following equation calculates the total costs accrued over time:
```
(Number of pods) * (pod size) * (number of replicas) * (minutes pod exists) * (pod price per minute)
+ (collection storage in GB) * (collection storage time in minutes) * (collection storage price per GB per minute)
```
To see a calculation of your current usage and costs, go to [**Settings > Usage**](https://app.pinecone.io/organizations/-/settings/usage) in the Pinecone console.
While our pricing page lists rates on an hourly basis for ease of comparison, this example lists prices per minute, as this is how Pinecone calculates billing.
An example application has the following requirements:
* 1,000,000 vectors with 1536 dimensions
* 150 queries per second with `top_k` = 10
* Deployment in an EU region
* Ability to store 1GB of inactive vectors
[Based on these requirements](/guides/indexes/pods/choose-a-pod-type-and-size), the organization chooses to configure the project to use the Standard billing plan to host one `p1.x2` pod with three replicas and a collection containing 1 GB of data. This project runs continuously for the month of January on the Standard plan. The components of the total cost for this example are given in Table 1 below:
**Table 1: Example billing components**
| Billing component | Value |
| ----------------------------- | ------------ |
| Number of pods | 1 |
| Number of replicas | 3 |
| Pod size | x2 |
| Total pod count | 6 |
| Minutes in January | 44,640 |
| Pod-minutes (pods \* minutes) | 267,840 |
| Pod price per minute | \$0.0012 |
| Collection storage | 1 GB |
| Collection storage minutes | 44,640 |
| Price per storage minute | \$0.00000056 |
The invoice for this example is given in Table 2 below:
**Table 2: Example invoice**
| Product | Quantity | Price per unit | Charge |
| ------------- | -------- | -------------- | -------- |
| Collections | 44,640 | \$0.00000056 | \$0.025 |
| P2 Pods (AWS) | 0 | | \$0.00 |
| P2 Pods (GCP) | 0 | | \$0.00 |
| S1 Pods | 0 | | \$0.00 |
| P1 Pods | 267,840 | \$0.0012 | \$514.29 |
Amount due \$514.54
## Known limitations
* [Pod storage capacity](#pod-types)
* Each **p1** pod has enough capacity for 1M vectors with 768 dimensions.
* Each **s1** pod has enough capacity for 5M vectors with 768 dimensions.
* [Metadata](/guides/index-data/indexing-overview#metadata)
* Metadata with high cardinality, such as a unique value for every vector in a large index, uses more memory than expected and can cause the pods to become full.
* [Collections](/guides/manage-data/back-up-an-index#pod-based-index-backups-using-collections)
* You cannot query or write to a collection after its creation. For this reason, a collection only incurs storage costs.
* You can only perform operations on collections in the current Pinecone project.
* [Sparse-dense vectors](/guides/search/hybrid-search#use-a-single-index-for-dense-and-sparse-vectors)
* Only `s1` and `p1` [pod-based indexes](/guides/indexes/pods/understanding-pod-based-indexes#pod-types) using the dotproduct distance metric support sparse-dense vectors.
# Manage cost
Source: https://docs.pinecone.io/guides/manage-cost/manage-cost
Reduce Pinecone spend with strategies like spend alerts, ID-prefix listing, multitenant namespaces, prepaid credits, and support cost optimization help.
For the latest pricing details, see our [pricing page](https://www.pinecone.io/pricing/).
For help estimating total cost, see [Understanding cost](/guides/manage-cost/understanding-cost). To view or download a detailed report of your current usage and costs, see [Monitor usage and costs](/guides/manage-cost/monitor-usage-and-costs#monitor-organization-level-usage).
To lower your bill, see [Ways to reduce cost](/guides/manage-cost/understanding-cost#ways-to-reduce-cost) and [Save on costs](/guides/optimize/save-on-costs), which cover available credits and discounts plus ways to optimize your workload.
## Set monthly spend alerts
You can set up email alerts to monitor your organization's monthly spending. These alerts notify designated recipients when spending reaches specified thresholds. The alerts automatically reset at the start of each monthly billing cycle.
Spend alerts are available on the [Standard and Enterprise plans](https://www.pinecone.io/pricing/). They are not needed on the Starter or Builder plans, where usage is capped by plan quotas rather than billed per unit.
To set a spend alert:
1. Go to [Settings > Spend alerts](https://app.pinecone.io/organizations/-/settings/spend-alerts) in the Pinecone console
2. Click **+ Add Alert**.
3. Enter the dollar amount for the spend alert.
4. Enter the email addresses to send the alert to. [Organization owners](/guides/organizations/understanding-organizations#organization-roles) are listed by default.
5. Click **Create**.
To edit a spend alert:
1. In the row of the spend alert you want to edit, click **ellipsis (...) menu > Edit**.
2. Change the dollar amount and/or email addresses for the spend alert.
3. Click **Update**.
**Auto-spend spike alert**: To protect from unexpected cost increases, Pinecone sends an alert when spending exceeds double your previous month's invoice amount. While the alert threshold is fixed and the alert cannot be deleted, you can modify which email addresses receive the alert and enable or disable the alert notifications.
## List by ID prefix
By using a [hierarchical ID schema](/guides/index-data/data-modeling#use-structured-ids), you can retrieve records without performing a query. To do so, you can use [`list`](/reference/api/latest/data-plane/list) to retrieve records by ID prefix, then use `fetch` to retrieve the records you need. This can reduce costs, because [`query` consumes more RUs when scanning a larger namespace](/guides/manage-cost/understanding-cost#query), while [`fetch` consumes a fixed ratio of RUs to records retrieved](/guides/manage-cost/understanding-cost#fetch).
## Use namespaces for multitenancy
If your application requires you to isolate the data of each customer/user, consider [implementing multitenancy with serverless indexes and namespaces](/guides/index-data/implement-multitenancy). With serverless indexes, you pay only for the amount of data stored and operations performed. For queries in particular, the cost is partly based on the total number of records that must be scanned, so using namespaces can significantly reduce query costs.
## Prepaid credits
Pinecone offers an incentive for customers who purchase prepaid credits with an upfront payment. Customers may purchase between \$8,000 and \$25,000 in prepaid credits.
Customers who purchase prepaid credits can unlock additional usage capacity at no extra cost. The available benefits vary based on the selected plan and prepaid amount.
Prepaid credits apply to Pinecone services at List Price. Any usage that exceeds the available prepaid credits will be billed at full List Price.
Customers on Standard and Enterprise pay-as-you-go plans can purchase prepaid credits directly by navigating in the Pinecone console to [Settings > Billing > Plans](https://app.pinecone.io/organizations/-/settings/billing/plans).
Purchasing prepaid credits is not available through cloud marketplace billing. To purchase prepaid credits through a cloud marketplace, contact [ar@pinecone.io](mailto:ar@pinecone.io).
## Talk to support
Users on Standard and Enterprise plans can [contact Support](https://app.pinecone.io/organizations/-/settings/support/ticket) for help in optimizing costs.
## See also
* [Understanding cost](/guides/manage-cost/understanding-cost)
* [Monitor usage and costs](/guides/manage-cost/monitor-usage-and-costs)
* [Save on costs](/guides/optimize/save-on-costs)
# Monitor usage and costs
Source: https://docs.pinecone.io/guides/manage-cost/monitor-usage-and-costs
Monitor Pinecone usage and costs at the organization, index, and operation level by tracking read units, write units, and storage consumption.
## Monitor organization-level usage and costs
To view usage and costs across your Pinecone organization, you must be an [organization owner or billing admin](/guides/organizations/understanding-organizations#organization-roles). Also, this feature is available only to organizations on the Standard or Enterprise plans.
The **Usage** dashboard in the Pinecone console gives you a detailed report of usage and costs across your organization, broken down by each billable SKU or aggregated by project or service. You can view the report in the console or download it as a CSV file for more detailed analysis.
1. Go to [**Settings > Usage**](https://app.pinecone.io/organizations/-/settings/usage) in the Pinecone console.
2. Select the time range to report on. This defaults to the last 30 days.
3. Select the scope for your report:
* **SKU:** The usage and cost for each billable SKU, for example, read units per cloud region, storage size per cloud region, or tokens per embedding model.
* **Project:** The aggregated cost for each project in your organization.
* **Service:** The aggregated cost for each service your organization uses, for example, database (includes serverless back up and restore), assistants, inference (embedding and reranking), and collections.
4. Choose the specific SKUs, projects, or services you want to report on. This defaults to all.
5. To download the report as a CSV file, click **Download**.
The CSV download provides more granular detail than the console view, including breakdowns by individual index as well as project and index tags.
Dates are shown in UTC to match billing invoices. Cost data is delayed up to three days from the actual usage date.
## Monitor index-level usage
You can monitor index-level usage directly in the Pinecone console, or you can pull them into [Prometheus](https://prometheus.io/). For more details, see [Monitoring](/guides/production/monitoring).
## Monitor operation-level usage
### Read units
[Query](/guides/search/search-overview), [fetch](/guides/manage-data/fetch-data), and [list by ID](/guides/manage-data/list-record-ids) requests return a `usage` parameter with the [read unit](/guides/manage-cost/understanding-cost#read-units) consumption of each request that is made.
While Pinecone tracks read unit usage with decimal precision, the Pinecone API and SDKs round these values up to the nearest whole number in query, fetch, and list responses. For example, if a query uses 0.45 read units, the API and SDKs will report it as 1 read unit.
For precise read unit reporting, see [index-level metrics](/guides/production/monitoring) or the organization-wide [Usage dashboard](/guides/manage-cost/monitor-usage-and-costs#monitor-organization-level-usage-and-costs).
Indexes built on [Dedicated Read Nodes](/guides/index-data/dedicated-read-nodes) are not subject to read unit limits for query, fetch, and list operations. For sizing and capacity planning guidance, see the [Dedicated Read Nodes](/guides/index-data/dedicated-read-nodes) guide.
Example query request:
```Python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
index = pc.Index("example-index")
response = index.query(
vector=[0.22,0.43,0.16,1,...],
namespace='example-namespace',
top_k=3,
include_values=False,
include_metadata=False
)
print(response)
```
```JavaScript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({ apiKey: "YOUR_API_KEY" })
const index = pc.index("example-index")
const queryResponse = await index.namespace('example-namespace').query({
vector: [0.22,0.43,0.16,1,...],
topK: 3,
includeValues: false,
includeMetadata: false,
});
console.log(queryResponse);
```
```java Java theme={null}
import io.pinecone.clients.Index;
import io.pinecone.configs.PineconeConfig;
import io.pinecone.configs.PineconeConnection;
import io.pinecone.unsigned_indices_model.QueryResponseWithUnsignedIndices;
import java.util.Arrays;
import java.util.List;
public class QueryByVector {
public static void main(String[] args) {
PineconeConfig config = new PineconeConfig("YOUR_API_KEY");
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
config.setHost("INDEX_HOST");
PineconeConnection connection = new PineconeConnection(config);
Index index = new Index(config, connection, "example-index");
List query = Arrays.asList(0.22f,0.43f,0.16f,1f,...);
QueryResponseWithUnsignedIndices queryResponse = index.query(3, query, null, null, null, "example-namespace", null, false, false);
System.out.println(queryResponse);
}
}
```
```go Go theme={null}
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func prettifyStruct(obj interface{}) string {
bytes, _ := json.MarshalIndent(obj, "", " ")
return string(bytes)
}
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
idxConnection, err := pc.Index(pinecone.NewIndexConnParams{Host: "INDEX_HOST", Namespace: "example-namespace"})
if err != nil {
log.Fatalf("Failed to create IndexConnection for Host: %v", err)
}
queryVector := []float32{0.22, 0.43, 0.16, 1, ...}
res, err := idxConnection.QueryByVectorValues(ctx, &pinecone.QueryByVectorValuesRequest{
Vector: queryVector,
TopK: 3,
IncludeValues: false,
})
if err != nil {
log.Fatalf("Error encountered when querying by vector: %v", err)
} else {
fmt.Printf(prettifyStruct(res))
}
```
The response looks like this:
```python Python theme={null}
{'matches': [{'id': 'record_193027', 'score': 0.00405937387, 'values': []},
{'id': 'record_137452', 'score': 0.00405937387, 'values': []},
{'id': 'record_132264', 'score': 0.00405937387, 'values': []}],
'namespace': 'example-namespace',
'usage': {'read_units': 1}}
```
```javascript JavaScript theme={null}
{
matches: [
{
id: 'record_186225',
score: 0.00405937387,
values: [],
sparseValues: undefined,
metadata: undefined
},
{
id: 'record_164994',
score: 0.00405937387,
values: [],
sparseValues: undefined,
metadata: undefined
},
{
id: 'record_186333',
score: 0.00405937387,
values: [],
sparseValues: undefined,
metadata: undefined
}
],
namespace: 'example-namespace',
usage: { readUnits: 1 }
}
```
```java Java theme={null}
class QueryResponseWithUnsignedIndices {
matches: [ScoredVectorWithUnsignedIndices {
score: 0.004059374
id: record_170370
values: []
metadata:
sparseValuesWithUnsignedIndices: SparseValuesWithUnsignedIndices {
indicesWithUnsigned32Int: []
values: []
}
}, ScoredVectorWithUnsignedIndices {
score: 0.004059374
id: record_107423
values: []
metadata:
sparseValuesWithUnsignedIndices: SparseValuesWithUnsignedIndices {
indicesWithUnsigned32Int: []
values: []
}
}, ScoredVectorWithUnsignedIndices {
score: 0.004059374
id: record_171426
values: []
metadata:
sparseValuesWithUnsignedIndices: SparseValuesWithUnsignedIndices {
indicesWithUnsigned32Int: []
values: []
}
}]
namespace: example-index
usage: read_units: 1
}
```
```go Go theme={null}
{
"matches": [
{
"vector": {
"id": "record_193027"
},
"score": 0.004059374
},
{
"vector": {
"id": "record_137452"
},
"score": 0.004059374
},
{
"vector": {
"id": "record_132264"
},
"score": 0.004059374
}
],
"usage": {
"read_units": 1
},
"namespace": "example-index"
}
```
For a more in-depth demonstration of how to use read units to inspect read costs, see [this notebook](https://github.com/pinecone-io/examples/blob/master/docs/read-units-demonstrated.ipynb).
### Egress
[Query](/guides/search/search-overview), [fetch](/guides/manage-data/fetch-data), [list](/guides/manage-data/list-record-ids), and [text search](/reference/api/latest/data-plane/search_records) requests return the [egress](/guides/manage-cost/understanding-cost#egress) consumed by each request in the `usage` object, as `egressBytes` (the total bytes returned by the operation, including IDs, scores, values, and metadata).
Egress is reported only on serverless reads that return record data. It is omitted on empty results and on requests that return no record data (such as index statistics and management requests).
### Embedding tokens
Requests to one of [Pinecone's hosted embedding models](/guides/index-data/create-an-index#embedding-models), either directly via the [`embed` operation](/reference/api/latest/inference/generate-embeddings) or automatically when upserting or querying an [index with integrated embedding](/guides/index-data/indexing-overview#integrated-embedding), return a `usage` parameter with the total tokens generated.
For example, the following request to use the `multilingual-e5-large` model to generate embeddings for sentences related to the word “apple” might return this request and summary of embedding tokens generated:
```python Python theme={null}
# Import the Pinecone library
from pinecone.grpc import PineconeGRPC as Pinecone
from pinecone import ServerlessSpec
import time
# Initialize a Pinecone client with your API key
pc = Pinecone(api_key="YOUR_API_KEY")
# Define a sample dataset where each item has a unique ID and piece of text
data = [
{"id": "vec1", "text": "Apple is a popular fruit known for its sweetness and crisp texture."},
{"id": "vec2", "text": "The tech company Apple is known for its innovative products like the iPhone."},
{"id": "vec3", "text": "Many people enjoy eating apples as a healthy snack."},
{"id": "vec4", "text": "Apple Inc. has revolutionized the tech industry with its sleek designs and user-friendly interfaces."},
{"id": "vec5", "text": "An apple a day keeps the doctor away, as the saying goes."},
{"id": "vec6", "text": "Apple Computer Company was founded on April 1, 1976, by Steve Jobs, Steve Wozniak, and Ronald Wayne as a partnership."}
]
# Convert the text into numerical vectors that Pinecone can index
embeddings = pc.inference.embed(
model="llama-text-embed-v2",
inputs=[d['text'] for d in data],
parameters={"input_type": "passage", "truncate": "END"}
)
print(embeddings)
```
```javascript JavaScript theme={null}
// Import the Pinecone library
import { Pinecone } from '@pinecone-database/pinecone';
// Initialize a Pinecone client with your API key
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' });
// Define a sample dataset where each item has a unique ID and piece of text
const data = [
{ id: 'vec1', text: 'Apple is a popular fruit known for its sweetness and crisp texture.' },
{ id: 'vec2', text: 'The tech company Apple is known for its innovative products like the iPhone.' },
{ id: 'vec3', text: 'Many people enjoy eating apples as a healthy snack.' },
{ id: 'vec4', text: 'Apple Inc. has revolutionized the tech industry with its sleek designs and user-friendly interfaces.' },
{ id: 'vec5', text: 'An apple a day keeps the doctor away, as the saying goes.' },
{ id: 'vec6', text: 'Apple Computer Company was founded on April 1, 1976, by Steve Jobs, Steve Wozniak, and Ronald Wayne as a partnership.' }
];
// Convert the text into numerical vectors that Pinecone can index
const model = 'llama-text-embed-v2';
const embeddings = await pc.inference.embed(
model,
data.map(d => d.text),
{ inputType: 'passage', truncate: 'END' }
);
console.log(embeddings);
```
```java Java theme={null}
// Import the required classes
import io.pinecone.clients.Index;
import io.pinecone.clients.Inference;
import io.pinecone.clients.Pinecone;
import org.openapitools.inference.client.ApiException;
import org.openapitools.inference.client.model.Embedding;
import org.openapitools.inference.client.model.EmbeddingsList;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
public class GenerateEmbeddings {
public static void main(String[] args) throws ApiException {
// Initialize a Pinecone client with your API key
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
Inference inference = pc.getInferenceClient();
// Prepare input sentences to be embedded
List data = Arrays.asList(
new DataObject("vec1", "Apple is a popular fruit known for its sweetness and crisp texture."),
new DataObject("vec2", "The tech company Apple is known for its innovative products like the iPhone."),
new DataObject("vec3", "Many people enjoy eating apples as a healthy snack."),
new DataObject("vec4", "Apple Inc. has revolutionized the tech industry with its sleek designs and user-friendly interfaces."),
new DataObject("vec5", "An apple a day keeps the doctor away, as the saying goes."),
new DataObject("vec6", "Apple Computer Company was founded on April 1, 1976, by Steve Jobs, Steve Wozniak, and Ronald Wayne as a partnership.")
);
List inputs = data.stream()
.map(DataObject::getText)
.collect(Collectors.toList());
// Specify the embedding model and parameters
String embeddingModel = "llama-text-embed-v2";
Map parameters = new HashMap<>();
parameters.put("input_type", "passage");
parameters.put("truncate", "END");
// Generate embeddings for the input data
EmbeddingsList embeddings = inference.embed(embeddingModel, parameters, inputs);
// Get embedded data
List embeddedData = embeddings.getData();
}
private static List convertBigDecimalToFloat(List bigDecimalValues) {
return bigDecimalValues.stream()
.map(BigDecimal::floatValue)
.collect(Collectors.toList());
}
}
class DataObject {
private String id;
private String text;
public DataObject(String id, String text) {
this.id = id;
this.text = text;
}
public String getId() {
return id;
}
public String getText() {
return text;
}
}
```
```go Go theme={null}
package main
// Import the required packages
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
type Data struct {
ID string
Text string
}
type Query struct {
Text string
}
func prettifyStruct(obj interface{}) string {
bytes, _ := json.MarshalIndent(obj, "", " ")
return string(bytes)
}
func main() {
ctx := context.Background()
// Initialize a Pinecone client with your API key
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
// Define a sample dataset where each item has a unique ID and piece of text
data := []Data{
{ID: "vec1", Text: "Apple is a popular fruit known for its sweetness and crisp texture."},
{ID: "vec2", Text: "The tech company Apple is known for its innovative products like the iPhone."},
{ID: "vec3", Text: "Many people enjoy eating apples as a healthy snack."},
{ID: "vec4", Text: "Apple Inc. has revolutionized the tech industry with its sleek designs and user-friendly interfaces."},
{ID: "vec5", Text: "An apple a day keeps the doctor away, as the saying goes."},
{ID: "vec6", Text: "Apple Computer Company was founded on April 1, 1976, by Steve Jobs, Steve Wozniak, and Ronald Wayne as a partnership."},
}
// Specify the embedding model and parameters
embeddingModel := "llama-text-embed-v2"
docParameters := pinecone.EmbedParameters{
InputType: "passage",
Truncate: "END",
}
// Convert the text into numerical vectors that Pinecone can index
var documents []string
for _, d := range data {
documents = append(documents, d.Text)
}
docEmbeddingsResponse, err := pc.Inference.Embed(ctx, &pinecone.EmbedRequest{
Model: embeddingModel,
TextInputs: documents,
Parameters: docParameters,
})
if err != nil {
log.Fatalf("Failed to embed documents: %v", err)
} else {
fmt.Printf(prettifyStruct(docEmbeddingsResponse))
}
}
```
```shell curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl https://api.pinecone.io/embed \
-H "Api-Key: $PINECONE_API_KEY" \
-H "Content-Type: application/json" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"model": "llama-text-embed-v2",
"parameters": {
"input_type": "passage",
"truncate": "END"
},
"inputs": [
{"text": "Apple is a popular fruit known for its sweetness and crisp texture."},
{"text": "The tech company Apple is known for its innovative products like the iPhone."},
{"text": "Many people enjoy eating apples as a healthy snack."},
{"text": "Apple Inc. has revolutionized the tech industry with its sleek designs and user-friendly interfaces."},
{"text": "An apple a day keeps the doctor away, as the saying goes."},
{"text": "Apple Computer Company was founded on April 1, 1976, by Steve Jobs, Steve Wozniak, and Ronald Wayne as a partnership."}
]
}'
```
The returned object looks like this:
```python Python theme={null}
EmbeddingsList(
model='llama-text-embed-v2',
data=[
{'values': [0.04925537109375, -0.01313018798828125, -0.0112762451171875, ...]},
...
],
usage={'total_tokens': 130}
)
```
```javascript JavaScript theme={null}
EmbeddingsList(1) [
{
values: [
0.04925537109375,
-0.01313018798828125,
-0.0112762451171875,
...
]
},
...
model: 'llama-text-embed-v2',
data: [ { values: [Array] } ],
usage: { totalTokens: 130 }
]
```
```java Java theme={null}
class EmbeddingsList {
model: llama-text-embed-v2
data: [class Embedding {
values: [0.04925537109375, -0.01313018798828125, -0.0112762451171875, ...]
additionalProperties: null
}, ...]
usage: class EmbeddingsListUsage {
totalTokens: 130
additionalProperties: null
}
additionalProperties: null
}
```
```go Go theme={null}
{
"data": [
{
"values": [
0.03942871,
-0.010177612,
-0.046051025,
...
]
},
...
],
"model": "llama-text-embed-v2",
"usage": {
"total_tokens": 130
}
}
```
```json curl theme={null}
{
"data": [
{
"values": [
0.04925537109375,
-0.01313018798828125,
-0.0112762451171875,
...
]
},
...
],
"model": "llama-text-embed-v2",
"usage": {
"total_tokens": 130
}
}
```
## See also
* [Understanding cost](/guides/manage-cost/understanding-cost)
* [Manage cost](/guides/manage-cost/manage-cost)
# Understanding cost
Source: https://docs.pinecone.io/guides/manage-cost/understanding-cost
Understand how costs are incurred in Pinecone, including read units (RUs), write units (WUs), storage, egress, and embedding.
For the latest pricing details, see [Pricing](https://www.pinecone.io/pricing/).
Pinecone serverless is usage-based, so you pay only for the data you store and the operations you run. Idle indexes cost nothing. Most early and small workloads fit within the free [Starter plan](https://www.pinecone.io/pricing/), and you can lower costs further as you scale.
## Ways to reduce cost
* **Start free.** The Starter plan has no monthly minimum, so you can build and test before committing to any spend.
* **Prepaid credits and annual commitments.** Committing usage upfront earns discounted rates. See [Prepaid credits](#prepaid-credits).
* **Bulk import credit.** Standard and Enterprise organizations receive a one-time 1 TB import credit for loading data from object storage. See [Imports](#imports).
* **Optimize your workload.** Use namespaces and right-size your reads to cut ongoing query cost. See [Save on costs](/guides/optimize/save-on-costs).
* **Talk to us.** Standard and Enterprise customers can [contact Support](https://app.pinecone.io/organizations/-/settings/support/ticket) to optimize costs and discuss volume discounts.
## Minimum usage
The Builder, Standard, and Enterprise [pricing plans](https://www.pinecone.io/pricing/) include a monthly minimum usage commitment:
| Plan | Minimum usage |
| ---------- | ----------------- |
| Starter | \$0/month |
| Builder | \$20/month (flat) |
| Standard | \$50/month |
| Enterprise | \$500/month |
On the Builder plan, the monthly minimum is a flat fee that covers included usage; additional usage beyond [Builder limits](/reference/api/database-limits) is blocked rather than billed. On the Standard and Enterprise plans, customers are charged for what they use each month beyond the monthly minimum.
The minimum is a commitment you grow into rather than an extra charge. Once your usage exceeds the minimum, you pay only for what you use.
**Examples**
* You are on the Standard plan.
* Your usage for the month of August amounts to \$20.
* Your usage is below the \$50 monthly minimum, so your total for the month is \$50.
In this case, the August invoice would include line items for each service you used (totaling \$20), plus a single line item covering the rest of the minimum usage commitment (\$30).
* You are on the Standard plan.
* Your usage for the month of August amounts to \$100.
* Your usage exceeds the \$50 monthly minimum, so your total for the month is \$100.
In this case, the August invoice would only show line items for each service you used (totaling \$100). Since your usage exceeds the minimum usage commitment, you are only charged for your actual usage and no additional minimum usage line item appears on your invoice.
## Prepaid credits
Pinecone offers an incentive for customers who purchase prepaid credits with an upfront payment. Customers may purchase between \$8,000 and \$25,000 in prepaid credits.
Customers who purchase prepaid credits can unlock additional usage capacity at no extra cost. The available benefits vary based on the selected plan and prepaid amount.
Prepaid credits apply to Pinecone services at List Price. Any usage that exceeds the available prepaid credits will be billed at full List Price.
Customers on Standard and Enterprise pay-as-you-go plans can purchase prepaid credits directly by navigating in the Pinecone console to [Settings > Billing > Plans](https://app.pinecone.io/organizations/-/settings/billing/plans).
Purchasing prepaid credits is not available through cloud marketplace billing. To purchase prepaid credits through a cloud marketplace, contact [ar@pinecone.io](mailto:ar@pinecone.io).
## Serverless indexes
With serverless indexes, you pay for the amount of data stored and operations performed, based on four usage metrics: [read units](#read-units), [write units](#write-units), [storage](#storage), and [egress](#egress).
For the latest serverless pricing rates, see [Pricing](https://www.pinecone.io/pricing/).
### Read units
A **read unit (RU)** is the unit Pinecone uses to measure and price the cost of a read request. Read units (RUs) measure the compute, I/O, and network resources consumed by the following read requests:
* [Query](#query)
* [Fetch](#fetch)
* [List](#list)
Read requests return the number of RUs used. You can use this information to [monitor read costs](/guides/manage-cost/monitor-usage-and-costs#read-units).
Indexes built on [Dedicated Read Nodes](/guides/index-data/dedicated-read-nodes) are not subject to read unit limits for query, fetch, and list operations. For sizing and capacity planning guidance, see the [Dedicated Read Nodes](/guides/index-data/dedicated-read-nodes) guide.
#### Query
The cost of a query scales linearly with the size of the targeted namespace. Specifically, a query uses 1 RU for every 1 GB of namespace size, with a minimum of 0.25 RUs per query.
| Namespace size | Read units per query |
| :------------- | :------------------- |
| \< 0.25 GB | 0.25 RUs (minimum) |
| 1 GB | 1 RU |
| 10 GB | 10 RUs |
| 50 GB | 50 RUs |
| 100 GB | 100 RUs |
To learn how to calculate your namespace size, see [Storage](#storage).
Parameters that affect the size of the query response, such as `top_k`, `include_metadata`, and `include_values`, are not relevant for query cost; only the size of the namespace determines the number of RUs used.
#### Fetch
A fetch request uses 1 RU for every 10 records fetched, for example:
| Fetched records | RUs |
| --------------- | --- |
| 10 | 1 |
| 50 | 5 |
| 107 | 11 |
Specifying a non-existent ID or adding the same ID more than once does not increase the number of RUs used. However, a fetch request will always use at least 1 RU.
[Fetching records by metadata](/guides/manage-data/fetch-data#fetch-records-by-metadata) uses the same cost model as fetching by ID: 1 RU for every 10 records fetched.
#### List
List has a fixed cost of 1 RU per call, with up to 100 records per call.
### Write units
A **write unit (WU)** is the unit Pinecone uses to measure and price the cost of a write request. Write units (WUs) measure the storage and compute resources used by the following write requests:
* [Upsert](#upsert)
* [Update](#update)
* [Delete](#delete)
#### Upsert
An upsert request uses 1 WU for each 1 KB of the request, with a minimum of 5 WUs per request. When an upsert modifies an existing record, the request uses 1 WU for each 1 KB of the existing record as well.
For example, the following table shows the WUs used by upsert requests at different batch sizes and record sizes, assuming all records are new:
| Records per batch | Dimension | Avg. metadata size | Avg. record size | WUs |
| :---------------- | :-------- | :----------------- | :--------------- | :--- |
| 1 | 768 | 100 bytes | 3.2 KB | 5 |
| 2 | 768 | 100 bytes | 3.2 KB | 7 |
| 10 | 1024 | 15,000 bytes | 19.10 KB | 191 |
| 100 | 768 | 500 bytes | 3.57 KB | 357 |
| 1000 | 1536 | 1000 bytes | 7.14 KB | 7140 |
#### Update
An update request uses 1 WU for each 1 KB of the new and existing record, with a minimum of 5 WUs per request.
For example, the following table shows the WUs used by an update at different record sizes:
| New record size | Previous record size | WUs |
| :-------------- | :------------------- | :-- |
| 6.24 KB | 6.50 KB | 13 |
| 19.10 KB | 15 KB | 25 |
| 3.57 KB | 5 KB | 9 |
| 7.14 KB | 10 KB | 18 |
| 3.17 KB | 3.17 KB | 7 |
[Updating records by metadata](/guides/manage-data/update-data#update-by-metadata) uses the same cost model as updating by ID: 1 WU for each 1 KB of the new and existing record.
#### Delete
A delete request uses 1 WU for each 1 KB of records deleted, with a minimum of 5 WUs per request.
For example, the following table shows the WUs used by delete requests at different batch sizes and record sizes:
| Records per batch | Dimension | Avg. metadata size | Avg. record size | WUs |
| :---------------- | :-------- | :----------------- | :--------------- | :--- |
| 1 | 768 | 100 bytes | 3.2 KB | 5 |
| 2 | 768 | 100 bytes | 3.2 KB | 7 |
| 10 | 1024 | 15,000 bytes | 19.10 KB | 191 |
| 100 | 768 | 500 bytes | 3.57 KB | 357 |
| 1000 | 1536 | 1000 bytes | 7.14 KB | 7140 |
Specifying a non-existent ID or adding the same ID more than once does not increase WU use.
[Deleting a namespace](/guides/manage-data/manage-namespaces#delete-a-namespace) or [deleting all records in a namespace using `deleteAll`](/guides/manage-data/delete-data#delete-all-records-in-a-namespace) uses 5 WUs.
[Deleting records by metadata](/guides/manage-data/delete-data#delete-records-by-metadata) uses the same cost model as deleting by ID: 1 WU for each 1 KB of records deleted.
### Storage
Storage costs are based on the size of an index on a per-gigabyte (GB) monthly rate. The size of an index is defined as the total size of its records across all namespaces. For the latest storage pricing rates, see [Pricing](https://www.pinecone.io/pricing/).
A record can include a dense vector, a sparse vector, or both. Use the formula that matches your data to calculate total size:
An [index of dense vectors](/guides/index-data/indexing-overview#indexes-with-dense-vectors) contains records with one dense vector each.
Records can also contain sparse vectors (when the index metric is set to `dotproduct`), which can be useful for [hybrid search](/guides/search/hybrid-search#use-a-single-index-for-dense-and-sparse-vectors). To learn how to calculate size in that case, see [Index with both dense and sparse vectors](#index-with-both-dense-and-sparse-vectors).
**Calculate size (assuming no sparse vectors)**
```
Index size = Number of records × (
ID size +
Metadata size +
Dense vector dimensions × 4 bytes
)
```
Where:
* `ID size` and `Metadata size` are measured in bytes, averaged across all records.
* Each `Dense vector dimension` uses 4 bytes.
**Example calculations**
These examples assume 8-byte IDs:
| Records | Dense vector dimensions | Avg metadata size | Index size |
| :--------- | :---------------------- | :---------------- | :--------- |
| 500,000 | 768 | 500 bytes | 1.79 GB |
| 1,000,000 | 1536 | 1,000 bytes | 7.15 GB |
| 5,000,000 | 1024 | 15,000 bytes | 95.5 GB |
| 10,000,000 | 1536 | 1,000 bytes | 71.5 GB |
Example: 500,000 records × (8-byte ID + (768 dense vector dimensions × 4 bytes) + 500 bytes of metadata) = 1.79 GB
An [index of sparse vectors](/guides/index-data/indexing-overview#indexes-with-sparse-vectors) contains records with one sparse vector each.
**Calculate size**
```
Index size = Number of records × (
ID size +
Metadata size +
Number of non-zero sparse values × 8 bytes
)
```
Where:
* `ID size` and `Metadata size` are measured in bytes, averaged across all records.
* `Number of non-zero sparse values`: Average number across all records. To find the count for a single record, check the length of the sparse vector's `indices` or `values` array. Each non-zero value uses 8 bytes.
**Example calculations**
These examples assume 8-byte IDs:
| Records | Avg number of non-zero sparse values | Avg metadata size | Index size |
| :--------- | :----------------------------------- | :---------------- | :--------- |
| 500,000 | 10 | 500 bytes | 0.29 GB |
| 1,000,000 | 50 | 1,000 bytes | 1.41 GB |
| 5,000,000 | 100 | 15,000 bytes | 79.0 GB |
| 10,000,000 | 50 | 1,000 bytes | 14.1 GB |
Example: 500,000 records × (8-byte ID + (10 non-zero sparse values × 8 bytes) + 500 bytes of metadata) = 0.29 GB
An [index with both dense and sparse vectors](/guides/search/hybrid-search#use-a-single-index-for-dense-and-sparse-vectors) contains records that each have one dense vector and an optional sparse vector.
**Calculate size**
```
Index size = Number of records × (
ID size +
Metadata size +
Dense vector dimensions × 4 bytes +
Number of non-zero sparse values × 8 bytes
)
```
Where:
* `ID size` and `Metadata size` are measured in bytes, averaged across all records.
* Each `Dense vector dimension` uses 4 bytes.
* `Number of non-zero sparse values`: Average number across all records, including those without sparse vectors. To find the count for a single record, check the length of the sparse vector's `indices` or `values` array. Each non-zero value uses 8 bytes.
**Example calculations**
These examples assume 8-byte IDs:
| Records | Dense vector dimensions | Avg number of non-zero sparse values | Avg metadata size | Index size |
| :--------- | :---------------------- | :----------------------------------- | :---------------- | :--------- |
| 500,000 | 768 | 10 | 500 bytes | 1.83 GB |
| 1,000,000 | 1536 | 50 | 1,000 bytes | 7.54 GB |
| 5,000,000 | 1024 | 100 | 15,000 bytes | 99.5 GB |
| 10,000,000 | 1536 | 50 | 1,000 bytes | 75.4 GB |
Example: 500,000 records × (8-byte ID + (768 dense vector dimensions × 4 bytes) + (10 non-zero sparse values × 8 bytes) + 500 bytes of metadata) = 1.83 GB
### Egress
**Egress** measures the data Pinecone returns to you on serverless reads. Egress is measured in GB of total response bytes returned by an in-scope read request, proportional to the record data returned (IDs, scores, values, and metadata).
Egress is metered on read requests that return per-record data:
* [Query](/guides/search/search-overview)
* [Fetch](/guides/manage-data/fetch-data) (by ID and by metadata)
* [List](/guides/manage-data/list-record-ids)
* [Text search](/reference/api/latest/data-plane/search_records) on integrated indexes
* [Full-text search](/guides/search/full-text-search)
Write requests (upsert, update, delete, import), index statistics (such as `describe_index_stats`), and index management requests are not metered for egress.
Egress accrues on all bytes returned by in-scope reads, including IDs, scores, and metadata. Setting `include_values=false` on a [fetch](/guides/manage-data/fetch-data#fetch-records) or query lowers egress but does not exempt the request, because IDs and metadata are still returned.
In-scope read requests return the egress consumed in the response `usage` object. You can use this information to [monitor egress](/guides/manage-cost/monitor-usage-and-costs#egress).
#### Egress allowance
Each plan includes a monthly egress allowance, which resets at the start of each billing period:
| Plan | Monthly egress allowance |
| :--------- | :----------------------- |
| Free | 1 GB |
| Builder | 10 GB |
| Standard | 100 GB |
| Enterprise | 100 GB |
What happens past the allowance depends on your plan:
* **Usage-based plans (Standard, Enterprise):** egress beyond the allowance is billed at the per-GB overage rate and reads keep serving. For the latest egress rate, see [Pricing](https://www.pinecone.io/pricing/).
* **Flat-fee plans (Free, Builder):** in-scope reads are blocked with a `RESOURCE_EXHAUSTED` (429) error and an upgrade prompt once the allowance is reached. Index statistics, index management, and write requests remain available, and the allowance resets at the start of the next billing period.
## Imports
[Importing from object storage](/guides/index-data/import-data) is the most efficient and cost-effective method to load large numbers of records into an index. The cost of an import is based on the size of the records read, whether the records were imported successfully or not.
If the import operation fails (e.g., after encountering a vector of the wrong dimension in an import with `on_error="abort"`), you will still be charged for the records read. However, if the import fails because of an internal system error, you will not incur charges. In this case, the import will return the error message `"We were unable to process your request. If the problem persists, please contact us at https://support.pinecone.io"`.
Standard and Enterprise organizations receive a **one-time 1 TB bulk import credit**, valid through August 30, 2026. Usage beyond the free allotment is billed at the standard import rate. Builder and Starter plans are not eligible.
For the latest import pricing rates, see [Pricing](https://www.pinecone.io/pricing/).
## Backups and restores
A [backup](/guides/manage-data/backups-overview) is a static copy of a serverless index. Both the cost of storing a backup and [restoring an index](/guides/manage-data/restore-an-index) from a backup is based on the size of the index. For the latest backup and restore pricing rates, see [Pricing](https://www.pinecone.io/pricing/).
## Embedding
Pinecone hosts several [embedding models](/guides/index-data/create-an-index#embedding-models) so it's easy to manage your vector storage and search process on a single platform. You can use a hosted model to embed your data as an integrated part of upserting and querying, or you can use a hosted model to embed your data as a standalone operation.
Embedding costs are determined by how many [tokens](https://www.pinecone.io/learn/tokenization/) are in a request. In general, the more words contained in your passage or query, the more tokens you generate.
For example, if you generate embeddings for the query, "What is the maximum diameter of a red pine?", Pinecone Inference generates 10 tokens, then converts them into an embedding. If the price per token for your billing plan is \$.08 per million tokens, then this API call costs \$.00001.
To learn more about tokenization, see [Choosing an embedding model](https://www.pinecone.io/learn/series/rag/embedding-models-rundown/). For the latest embed pricing rates, see [Pricing](https://www.pinecone.io/pricing/).
Embedding requests returns the total tokens generated. You can use this information to [monitor and manage embedding costs](/guides/manage-cost/monitor-usage-and-costs#embedding-tokens).
## Reranking
Pinecone hosts several [reranking models](/guides/search/rerank-results#reranking-models) so it's easy to manage two-stage vector retrieval on a single platform. You can use a hosted model to rerank results as an integrated part of a query, or you can use a hosted model to rerank results as a standalone operation.
Reranking costs are determined by the number of requests to the reranking model. For the latest rerank pricing rates, see [Pricing](https://www.pinecone.io/pricing/).
## Assistant
For details on how costs are incurred in Pinecone Assistant, see [Assistant pricing](/guides/assistant/pricing-and-limits).
## HIPAA compliance add-on
Full HIPAA compliance is included with the [Enterprise plan](https://www.pinecone.io/pricing/).
For **Standard plan** customers, HIPAA compliance is available as an optional add-on for **\$190 per month**. The add-on is billed monthly and added to your regular invoice. A 6-month minimum period is required.
The HIPAA compliance add-on includes:
* HIPAA-ready infrastructure
* Encrypted data storage
* Audit logging
* Enhanced security controls
* BAA execution and compliance documentation support
If you upgrade to the Enterprise plan, the HIPAA compliance add-on is automatically removed because HIPAA compliance is included with Enterprise.
### Enable the HIPAA compliance add-on
To enable the HIPAA compliance add-on, [contact sales](mailto:sales@pinecone.io) or [submit a request](https://www.pinecone.io/contact/?contact_form_inquiry_type=Sales). The Pinecone team will review your request and guide you through activation.
## See also
* [Manage cost](/guides/manage-cost/manage-cost)
* [Monitor usage](/guides/manage-cost/monitor-usage-and-costs)
* [Pricing](https://www.pinecone.io/pricing/)
# Back up an index
Source: https://docs.pinecone.io/guides/manage-data/back-up-an-index
Create backups of serverless indexes to protect data, copy indexes, or experiment with configurations using the Pinecone SDK, API, or console.
## Create a backup
You can [create a backup from a serverless index](/reference/api/latest/control-plane/create_backup) as follows.
Backups are supported for indexes without a schema definition and for integrated embedding indexes that use the records API. They are not supported for full-text search indexes with document schemas that include `full_text_search` string fields, `dense_vector` fields, or `sparse_vector` fields. Indexes with document schemas also do not support `semantic_text` fields.
```python Python theme={null}
from pinecone import Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
backup = pc.create_backup(
index_name="docs-example",
backup_name="example-backup",
description="Monthly backup of production index"
)
print(backup)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' })
const backup = await pc.createBackup({
indexName: 'docs-example',
name: 'example-backup',
description: 'Monthly backup of production index',
});
console.log(backup);
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.ApiException;
import org.openapitools.db_control.client.model.*;
public class CreateBackup {
public static void main(String[] args) throws ApiException {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
String indexName = "docs-example";
String backupName = "example-backup";
String backupDescription = "Monthly backup of production index";
BackupModel backup = pc.createBackup(indexName,backupName, backupDescription);
System.out.println(backup);
}
}
```
```go Go theme={null}
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func prettifyStruct(obj interface{}) string {
bytes, _ := json.MarshalIndent(obj, "", " ")
return string(bytes)
}
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
indexName := "docs-example"
backupName := "example-backup"
backupDesc := "Monthly backup of production index"
backup, err := pc.CreateBackup(ctx, &pinecone.CreateBackupParams{
IndexName: indexName,
Name: &backupName,
Description: &backupDesc,
})
if err != nil {
log.Fatalf("Failed to create backup: %v", err)
}
fmt.Printf(prettifyStruct(backup))
}
```
```bash curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_NAME="docs-example"
curl "https://api.pinecone.io/indexes/$INDEX_NAME/backups" \
-H "Api-Key: $PINECONE_API_KEY" \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"name": "example-backup",
"description": "Monthly backup of production index"
}'
```
The example returns a response like the following:
```python Python theme={null}
{'backup_id': '8c85e612-ed1c-4f97-9f8c-8194e07bcf71',
'cloud': 'aws',
'created_at': '2025-05-15T00:52:10.809305882Z',
'description': 'Monthly backup of production index',
'dimension': 1024,
'name': 'example-backup',
'namespace_count': 3,
'record_count': 98,
'region': 'us-east-1',
'size_bytes': 1069169,
'source_index_id': 'f73b36c9-faf5-4a2c-b1d6-4013d8b1cc74',
'source_index_name': 'docs-example',
'status': 'Ready',
'tags': {}}
```
```javascript JavaScript theme={null}
{
backupId: '8c85e612-ed1c-4f97-9f8c-8194e07bcf71',
sourceIndexName: 'docs-example',
sourceIndexId: 'f73b36c9-faf5-4a2c-b1d6-4013d8b1cc74',
name: 'example-backup',
description: 'Monthly backup of production index',
status: 'Ready',
cloud: 'aws',
region: 'us-east-1',
dimension: 1024,
metric: undefined,
recordCount: 98,
namespaceCount: 3,
sizeBytes: 1069169,
tags: {},
createdAt: '2025-05-14T16:37:25.625540Z'
}
```
```java Java theme={null}
class BackupModel {
backupId: 0d75b99f-be61-4a93-905e-77201286c02e
sourceIndexName: docs-example
sourceIndexId: f73b36c9-faf5-4a2c-b1d6-4013d8b1cc74
name: example-backup
description: Monthly backup of production index
status: Initializing
cloud: aws
region: us-east-1
dimension: null
metric: null
recordCount: null
namespaceCount: null
sizeBytes: null
tags: {}
createdAt: 2025-05-16T19:42:23.804787550Z
additionalProperties: null
}
```
```go Go theme={null}
{
"backup_id": "8c85e612-ed1c-4f97-9f8c-8194e07bcf71",
"cloud": "aws",
"created_at": "2025-05-15T00:52:10.809305882Z",
"description": "Monthly backup of production index",
"dimension": 1024,
"name": "example-backup",
"region": "us-east-1",
"source_index_id": "f73b36c9-faf5-4a2c-b1d6-4013d8b1cc74",
"source_index_name": "docs-example",
"status": "Initializing",
"tags": {}
}
```
```json curl theme={null}
{
"backup_id":"8c85e612-ed1c-4f97-9f8c-8194e07bcf71",
"source_index_id":"f73b36c9-faf5-4a2c-b1d6-4013d8b1cc74",
"source_index_name":"docs-example",
"tags":{},
"name":"example-backup",
"description":"Monthly backup of production index",
"status":"Ready",
"cloud":"aws",
"region":"us-east-1",
"dimension":1024,
"record_count":96,
"namespace_count":3,
"size_bytes":1069169,
"created_at":"2025-05-14T16:37:25.625540Z"
}
```
You can create a backup using the [Pinecone console](https://app.pinecone.io/organizations/-/projects/-/backups).
## Describe a backup
You can [view the details of a backup](/reference/api/latest/control-plane/describe_backup) as follows.
```python Python theme={null}
from pinecone import Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
backup = pc.describe_backup(backup_id="8c85e612-ed1c-4f97-9f8c-8194e07bcf71")
print(backup)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' })
const backupDesc = await pc.describeBackup('8c85e612-ed1c-4f97-9f8c-8194e07bcf71');
console.log(backupDesc);
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.ApiException;
import org.openapitools.db_control.client.model.*;
public class CreateBackup {
public static void main(String[] args) throws ApiException {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
BackupModel backupModel = pc.describeBackup("8c85e612-ed1c-4f97-9f8c-8194e07bcf71");
System.out.println(backupModel);
}
}
```
```go Go theme={null}
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func prettifyStruct(obj interface{}) string {
bytes, _ := json.MarshalIndent(obj, "", " ")
return string(bytes)
}
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
backup, err := pc.DescribeBackup(ctx, "8c85e612-ed1c-4f97-9f8c-8194e07bcf71")
if err != nil {
log.Fatalf("Failed to describe backup: %v", err)
}
fmt.Printf(prettifyStruct(backup))
}
```
```bash curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
BACKUP_ID="8c85e612-ed1c-4f97-9f8c-8194e07bcf71"
curl -X GET "https://api.pinecone.io/backups/$BACKUP_ID" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-H "accept: application/json"
```
The example returns a response like the following:
```python Python theme={null}
{'backup_id': '8c85e612-ed1c-4f97-9f8c-8194e07bcf71',
'cloud': 'aws',
'created_at': '2025-05-15T00:52:10.809354Z',
'description': 'Monthly backup of production index',
'dimension': 1024,
'name': 'example-backup',
'namespace_count': 3,
'record_count': 98,
'region': 'us-east-1',
'size_bytes': 1069169,
'source_index_id': 'f73b36c9-faf5-4a2c-b1d6-4013d8b1cc74',
'source_index_name': 'docs-example',
'status': 'Ready',
'tags': {}}
```
```javascript JavaScript theme={null}
{
backupId: '8c85e612-ed1c-4f97-9f8c-8194e07bcf71',
sourceIndexName: 'docs-example',
sourceIndexId: 'f73b36c9-faf5-4a2c-b1d6-4013d8b1cc74',
name: 'example-backup',
description: 'Monthly backup of production index',
status: 'Ready',
cloud: 'aws',
region: 'us-east-1',
dimension: 1024,
metric: undefined,
recordCount: 98,
namespaceCount: 3,
sizeBytes: 1069169,
tags: {},
createdAt: '2025-05-14T16:37:25.625540Z'
}
```
```java Java theme={null}
class BackupList {
data: [class BackupModel {
backupId: 95707edb-e482-49cf-b5a5-312219a51a97
sourceIndexName: docs-example
sourceIndexId: f73b36c9-faf5-4a2c-b1d6-4013d8b1cc74
name: example-backup
description: Monthly backup of production index
status: Initializing
cloud: aws
region: us-east-1
dimension: null
metric: null
recordCount: null
namespaceCount: null
sizeBytes: null
tags: {}
createdAt: 2025-05-16T19:46:26.248428Z
additionalProperties: null
}]
pagination: null
additionalProperties: null
}
```
```go Go theme={null}
{
"backup_id": "8c85e612-ed1c-4f97-9f8c-8194e07bcf71",
"cloud": "aws",
"created_at": "2025-05-15T00:52:10.809354Z",
"description": "Monthly backup of production index",
"dimension": 1024,
"name": "example-backup",
"namespace_count": 3,
"record_count": 98,
"region": "us-east-1",
"size_bytes": 1069169,
"source_index_id": "f73b36c9-faf5-4a2c-b1d6-4013d8b1cc74",
"source_index_name": "docs-example",
"status": "Ready",
"tags": {}
}
```
```json curl theme={null}
{
"backup_id":"8c85e612-ed1c-4f97-9f8c-8194e07bcf71",
"source_index_id":"f73b36c9-faf5-4a2c-b1d6-4013d8b1cc74",
"source_index_name":"docs-example",
"tags":{},
"name":"example-backup",
"description":"Monthly backup of production index",
"status":"Ready",
"cloud":"aws",
"region":"us-east-1",
"dimension":1024,
"record_count":98,
"namespace_count":3,
"size_bytes":1069169,
"created_at":"2025-03-11T18:29:50.549505Z"
}
```
You can view backup details using the [Pinecone console](https://app.pinecone.io/organizations/-/projects-/backups).
## List backups for an index
You can [list backups for a specific index](/reference/api/latest/control-plane/list_index_backups) as follows.
Up to 100 backups are returned at a time by default, in sorted order (bitwise “C” collation). If the `limit` parameter is set, up to that number of backups are returned instead. Whenever there are additional backups to return, the response also includes a `pagination_token` that you can use to get the next batch of backups. When the response does not include a `pagination_token`, there are no more backups to return.
```python Python theme={null}
from pinecone import Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
index_backups = pc.list_backups(index_name="docs-example")
print(index_backups)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' })
const indexBackups = await pc.listBackups({ indexName: 'docs-example' });
console.log(indexBackups);
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.ApiException;
import org.openapitools.db_control.client.model.*;
public class CreateBackup {
public static void main(String[] args) throws ApiException {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
String indexName = "docs-example";
BackupList indexBackupList = pc.listIndexBackups(indexName);
System.out.println(indexBackupList);
}
}
```
```go Go theme={null}
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func prettifyStruct(obj interface{}) string {
bytes, _ := json.MarshalIndent(obj, "", " ")
return string(bytes)
}
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
indexName := "docs-example"
limit := 2
indexBackups, err := pc.ListBackups(ctx, &pinecone.ListBackupsParams{
Limit: &limit,
IndexName: &indexName,
})
if err != nil {
log.Fatalf("Failed to list backups: %v", err)
}
fmt.Printf(prettifyStruct(indexBackups))
}
```
```bash curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_NAME="docs-example"
curl -X GET "https://api.pinecone.io/indexes/$INDEX_NAME/backups" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-H "accept: application/json"
```
The example returns a response like the following:
```python Python theme={null}
[{
"backup_id": "8c85e612-ed1c-4f97-9f8c-8194e07bcf71",
"source_index_name": "docs-example",
"source_index_id": "f73b36c9-faf5-4a2c-b1d6-4013d8b1cc74",
"status": "Ready",
"cloud": "aws",
"region": "us-east-1",
"tags": {},
"name": "example-backup",
"description": "Monthly backup of production index",
"dimension": 1024,
"record_count": 98,
"namespace_count": 3,
"size_bytes": 1069169,
"created_at": "2025-05-15T00:52:10.809305882Z"
}]
```
```javascript JavaScript theme={null}
{
data: [
{
backupId: '8c85e612-ed1c-4f97-9f8c-8194e07bcf71',
sourceIndexName: 'docs-example',
sourceIndexId: 'f73b36c9-faf5-4a2c-b1d6-4013d8b1cc74',
name: 'example-backup',
description: 'Monthly backup of production index',
status: 'Ready',
cloud: 'aws',
region: 'us-east-1',
dimension: 1024,
metric: undefined,
recordCount: 98,
namespaceCount: 3,
sizeBytes: 1069169,
tags: {},
createdAt: '2025-05-14T16:37:25.625540Z'
}
],
pagination: undefined
}
```
```java Java theme={null}
class BackupList {
data: [class BackupModel {
backupId: 8c85e612-ed1c-4f97-9f8c-8194e07bcf71
sourceIndexName: docs-example
sourceIndexId: f73b36c9-faf5-4a2c-b1d6-4013d8b1cc74
name: example-backup
description: Monthly backup of production index
status: Initializing
cloud: aws
region: us-east-1
dimension: null
metric: null
recordCount: null
namespaceCount: null
sizeBytes: null
tags: {}
createdAt: 2025-05-16T19:46:26.248428Z
additionalProperties: null
}]
pagination: null
additionalProperties: null
}
```
```go Go theme={null}
{
"data": [
{
"backup_id": "bf2cda5d-b233-4a0a-aae9-b592780ad3ff",
"cloud": "aws",
"created_at": "2025-05-16T18:01:51.531129Z",
"description": "Monthly backup of production index",
"dimension": 0,
"name": "example-backup",
"namespace_count": 1,
"record_count": 96,
"region": "us-east-1",
"size_bytes": 86393,
"source_index_id": "bcb5b3c9-903e-4cb6-8b37-a6072aeb874f",
"source_index_name": "docs-example",
"status": "Ready",
"tags": {}
},
{
"backup_id": "e12269b0-a29b-4af0-9729-c7771dec03e3",
"cloud": "aws",
"created_at": "2025-05-14T17:00:45.803146Z",
"dimension": 0,
"name": "example-backup2",
"namespace_count": 1,
"record_count": 96,
"region": "us-east-1",
"size_bytes": 86393,
"source_index_id": "bcb5b3c9-903e-4cb6-8b37-a6072aeb874f",
"source_index_name": "docs-example",
"status": "Ready"
}
],
"pagination": {
"next": "eyJsaW1pdCI6Miwib2Zmc2V0IjoyfQ=="
}
}
```
```json curl theme={null}
{
"data":
[
{
"backup_id":"9947520e-d5a1-4418-a78d-9f464c9969da",
"source_index_id":"8433941a-dae7-43b5-ac2c-d3dab4a56b2b",
"source_index_name":"docs-example",
"tags":{},
"name":"example-backup",
"description":"Monthly backup of production index",
"status":"Pending",
"cloud":"aws",
"region":"us-east-1",
"dimension":1024,
"record_count":98,
"namespace_count":3,
"size_bytes":1069169,
"created_at":"2025-03-11T18:29:50.549505Z"
}
],
"pagination":null
}
```
You can view the backups for a specific index from either the [Backups](https://app.pinecone.io/organizations/-/projects/-/backups) tab or the [Indexes](https://app.pinecone.io/organizations/-/projects/-/indexes) tab in the Pinecone console.
## List backups in a project
You can [list backups for all indexes in a project](/reference/api/latest/control-plane/list_project_backups) as follows.
Up to 100 backups are returned at a time by default, in sorted order (bitwise “C” collation). If the `limit` parameter is set, up to that number of backups are returned instead. Whenever there are additional backups to return, the response also includes a `pagination_token` that you can use to get the next batch of backups. When the response does not include a `pagination_token`, there are no more backups to return.
```python Python theme={null}
from pinecone import Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
project_backups = pc.list_backups()
print(project_backups)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' })
const projectBackups = await pc.listBackups();
console.log(projectBackups);
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.ApiException;
import org.openapitools.db_control.client.model.*;
public class CreateBackup {
public static void main(String[] args) throws ApiException {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
String indexName = "docs-example";
BackupList projectBackupList = pc.listProjectBackups();
System.out.println(projectBackupList);
}
}
```
```go Go theme={null}
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func prettifyStruct(obj interface{}) string {
bytes, _ := json.MarshalIndent(obj, "", " ")
return string(bytes)
}
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
limit := 3
backups, err := pc.ListBackups(ctx, &pinecone.ListBackupsParams{
Limit: &limit,
})
if err != nil {
log.Fatalf("Failed to list backups: %v", err)
}
fmt.Printf(prettifyStruct(backups))
}
```
```bash curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -X GET "https://api.pinecone.io/backups" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-H "accept: application/json"
```
The example returns a response like the following:
```python Python theme={null}
[{
"backup_id": "8c85e612-ed1c-4f97-9f8c-8194e07bcf71",
"source_index_name": "docs-example",
"source_index_id": "f73b36c9-faf5-4a2c-b1d6-4013d8b1cc74",
"status": "Ready",
"cloud": "aws",
"region": "us-east-1",
"tags": {},
"name": "example-backup",
"description": "Monthly backup of production index",
"dimension": 1024,
"record_count": 98,
"namespace_count": 3,
"size_bytes": 1069169,
"created_at": "2025-05-15T20:26:21.248515Z"
}, {
"backup_id": "95707edb-e482-49cf-b5a5-312219a51a97",
"source_index_name": "docs-example2",
"source_index_id": "b49f27d1-1bf3-49c6-82b5-4ae46f00f0e6",
"status": "Ready",
"cloud": "aws",
"region": "us-east-1",
"tags": {},
"name": "example-backup2",
"description": "Monthly backup of production index",
"dimension": 1024,
"record_count": 97,
"namespace_count": 2,
"size_bytes": 1069169,
"created_at": "2025-05-15T00:52:10.809354Z"
}, {
"backup_id": "8c85e612-ed1c-4f97-9f8c-8194e07bcf71",
"source_index_name": "docs-example3",
"source_index_id": "f73b36c9-faf5-4a2c-b1d6-4013d8b1cc74",
"status": "Ready",
"cloud": "aws",
"region": "us-east-1",
"tags": {},
"name": "example-backup3",
"description": "Monthly backup of production index",
"dimension": 1024,
"record_count": 98,
"namespace_count": 3,
"size_bytes": 1069169,
"created_at": "2025-05-14T16:37:25.625540Z"
}]
```
```javascript JavaScript theme={null}
{
data: [
{
backupId: 'e12269b0-a29b-4af0-9729-c7771dec03e3',
sourceIndexName: 'docs-example',
sourceIndexId: 'bcb5b3c9-903e-4cb6-8b37-a6072aeb874f',
name: 'example-backup',
description: undefined,
status: 'Ready',
cloud: 'aws',
region: 'us-east-1',
dimension: 0,
metric: undefined,
recordCount: 96,
namespaceCount: 1,
sizeBytes: 86393,
tags: undefined,
createdAt: '2025-05-14T17:00:45.803146Z'
},
{
backupId: 'd686451d-1ede-4004-9f72-7d22cc799b6e',
sourceIndexName: 'docs-example2',
sourceIndexId: 'b49f27d1-1bf3-49c6-82b5-4ae46f00f0e6',
name: 'example-backup2',
description: undefined,
status: 'Ready',
cloud: 'aws',
region: 'us-east-1',
dimension: 1024,
metric: undefined,
recordCount: 50,
namespaceCount: 1,
sizeBytes: 545171,
tags: undefined,
createdAt: '2025-05-14T17:00:34.814371Z'
},
{
backupId: '8c85e612-ed1c-4f97-9f8c-8194e07bcf71',
sourceIndexName: 'docs-example3',
sourceIndexId: 'f73b36c9-faf5-4a2c-b1d6-4013d8b1cc74',
name: 'example-backup3',
description: 'Monthly backup of production index',
status: 'Ready',
cloud: 'aws',
region: 'us-east-1',
dimension: 1024,
metric: undefined,
recordCount: 98,
namespaceCount: 3,
sizeBytes: 1069169,
tags: {},
createdAt: '2025-05-14T16:37:25.625540Z'
}
],
pagination: undefined
}
```
```java Java theme={null}
class BackupList {
data: [class BackupModel {
backupId: 13761d20-7a0b-4778-ac27-36dd91c4be43
sourceIndexName: example-dense-index
sourceIndexId: f73b36c9-faf5-4a2c-b1d6-4013d8b1cc74
name: example-backup
description: Monthly backup of production index
status: Initializing
cloud: aws
region: us-east-1
dimension: null
metric: null
recordCount: null
namespaceCount: null
sizeBytes: null
tags: {}
createdAt: 2025-05-16T19:46:26.248428Z
additionalProperties: null
}, class BackupModel {
backupId: 0d75b99f-be61-4a93-905e-77201286c02e
sourceIndexName: example-dense-index
sourceIndexId: f73b36c9-faf5-4a2c-b1d6-4013d8b1cc74
name: example-backup2
description: Monthly backup of production index
status: Initializing
cloud: aws
region: us-east-1
dimension: null
metric: null
recordCount: null
namespaceCount: null
sizeBytes: null
tags: {}
createdAt: 2025-05-16T19:42:23.804820Z
additionalProperties: null
}, class BackupModel {
backupId: bf2cda5d-b233-4a0a-aae9-b592780ad3ff
sourceIndexName: example-sparse-index
sourceIndexId: bcb5b3c9-903e-4cb6-8b37-a6072aeb874f
name: example-backup3
description: Monthly backup of production index
status: Ready
cloud: aws
region: us-east-1
dimension: 0
metric: null
recordCount: 96
namespaceCount: 1
sizeBytes: 86393
tags: {}
createdAt: 2025-05-16T18:01:51.531129Z
additionalProperties: null
}]
pagination: null
additionalProperties: null
}
```
```go Go theme={null}
{
"data": [
{
"backup_id": "8c85e612-ed1c-4f97-9f8c-8194e07bcf71",
"cloud": "aws",
"created_at": "2025-05-15T00:52:10.809305882Z",
"description": "Monthly backup of production index",
"dimension": 1024,
"name": "example-backup",
"namespace_count": 3,
"record_count": 98,
"region": "us-east-1",
"size_bytes": 1069169,
"source_index_id": "f73b36c9-faf5-4a2c-b1d6-4013d8b1cc74",
"source_index_name": "docs-example",
"status": "Ready",
"tags": {}
},
{
"backup_id": "bf2cda5d-b233-4a0a-aae9-b592780ad3ff",
"cloud": "aws",
"created_at": "2025-05-15T00:52:10.809305882Z",
"description": "Monthly backup of production index",
"dimension": 0,
"name": "example-backup2",
"namespace_count": 1,
"record_count": 96,
"region": "us-east-1",
"size_bytes": 86393,
"source_index_id": "bcb5b3c9-903e-4cb6-8b37-a6072aeb874f",
"source_index_name": "example-sparse-index",
"status": "Ready",
"tags": {}
},
{
"backup_id": "f73028f6-1746-410e-ab6d-9dd2519df4de",
"cloud": "aws",
"created_at": "2025-05-15T20:26:21.248515Z",
"description": "Monthly backup of production index",
"dimension": 1024,
"name": "example-backup3",
"namespace_count": 2,
"record_count": 97,
"region": "us-east-1",
"size_bytes": 1069169,
"source_index_id": "f73b36c9-faf5-4a2c-b1d6-4013d8b1cc74",
"source_index_name": "example-dense-index",
"status": "Ready",
"tags": {}
}
],
"pagination": {
"next": "eyJsaW1pdCI6Miwib2Zmc2V0IjoyfQ=="
}
}
```
```json curl theme={null}
{
"data": [
{
"backup_id": "e12269b0-a29b-4af0-9729-c7771dec03e3",
"source_index_id": "bcb5b3c9-903e-4cb6-8b37-a6072aeb874f",
"source_index_name": "docs-example",
"tags": null,
"name": "example-backup",
"description": null,
"status": "Ready",
"cloud": "aws",
"region": "us-east-1",
"dimension": 0,
"record_count": 96,
"namespace_count": 1,
"size_bytes": 86393,
"created_at": "2025-05-14T17:00:45.803146Z"
},
{
"backup_id": "d686451d-1ede-4004-9f72-7d22cc799b6e",
"source_index_id": "b49f27d1-1bf3-49c6-82b5-4ae46f00f0e6",
"source_index_name": "docs-example2",
"tags": null,
"name": "example-backup2",
"description": null,
"status": "Ready",
"cloud": "aws",
"region": "us-east-1",
"dimension": 1024,
"record_count": 50,
"namespace_count": 1,
"size_bytes": 545171,
"created_at": "2025-05-14T17:00:34.814371Z"
},
{
"backup_id": "8c85e612-ed1c-4f97-9f8c-8194e07bcf71",
"source_index_id": "f73b36c9-faf5-4a2c-b1d6-4013d8b1cc74",
"source_index_name": "docs-example3",
"tags": {},
"name": "example-backup3",
"description": "Monthly backup of production index",
"status": "Ready",
"cloud": "aws",
"region": "us-east-1",
"dimension": 1024,
"record_count": 98,
"namespace_count": 3,
"size_bytes": 1069169,
"created_at": "2025-05-14T16:37:25.625540Z"
}
],
"pagination": null
}
```
You can view all backups in a project using the [Pinecone console](https://app.pinecone.io/organizations/-/projects-/backups).
## Delete a backup
You can [delete a backup](/reference/api/latest/control-plane/delete_backup) as follows.
```python Python theme={null}
from pinecone import Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
pc.delete_backup(backup_id="9947520e-d5a1-4418-a78d-9f464c9969da")
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' })
await pc.deleteBackup('9947520e-d5a1-4418-a78d-9f464c9969da');
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.ApiException;
import org.openapitools.db_control.client.model.*;
public class CreateBackup {
public static void main(String[] args) throws ApiException {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
pc.deleteBackup("9947520e-d5a1-4418-a78d-9f464c9969da");
}
}
```
```go Go theme={null}
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func prettifyStruct(obj interface{}) string {
bytes, _ := json.MarshalIndent(obj, "", " ")
return string(bytes)
}
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
err = pc.DeleteBackup(ctx, "8c85e612-ed1c-4f97-9f8c-8194e07bcf71")
if err != nil {
log.Fatalf("Failed to delete backup: %v", err)
} else {
fmt.Println("Backup deleted successfully")
}
}
```
```bash curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
BACKUP_ID="9947520e-d5a1-4418-a78d-9f464c9969da"
curl -X DELETE "https://api.pinecone.io/backups/$BACKUP_ID" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10"
```
You can delete a backup using the [Pinecone console](https://app.pinecone.io/organizations/-/projects-/backups).
## Schedule automated backups
Instead of creating backups manually, you can define a recurring schedule that automatically creates backups at a daily, weekly, or monthly frequency. Each schedule includes a retention policy that automatically deletes old backups, keeping storage costs predictable. Each index supports one active schedule at a time.
### Create a backup schedule
1. Open the [Pinecone console](https://app.pinecone.io/organizations/-/projects/-/backups) and go to the **Backups** tab.
2. Find your index and, in the **Schedule** column, click **add**. Alternatively, select **Schedule backups** from the actions menu of the index.
3. In the **Add a backup schedule** modal, select a **Frequency** (daily, weekly, or monthly).
4. Select a **Retention** period. Each backup created by the schedule is automatically deleted after this period.
5. Click **Add schedule**.
Pinecone names the schedule and assigns its run time automatically.
The scheduled backups API requires `X-Pinecone-API-Version: unstable`.
To [create a backup schedule](/reference/api/2026-04/control-plane/create_backup_schedule):
```bash curl theme={null}
curl -sS -X POST "https://api.pinecone.io/indexes/${INDEX_NAME}/backup-schedules" \
-H "api-key: ${PINECONE_API_KEY}" \
-H "X-Pinecone-API-Version: unstable" \
-H "Content-Type: application/json" \
-d '{
"name": "my-nightly-backup",
"schedule": {
"type": "time-based",
"frequency": "daily"
},
"retention": {
"expire_after_days": 7
}
}'
```
Use `"frequency": "weekly"` or `"monthly"` as needed. The retention policy (`expire_after_days`) is required.
### Manage backup schedules
1. Open the [Pinecone console](https://app.pinecone.io/organizations/-/projects/-/backups) and go to the **Backups** tab.
2. Find your index and, in the **Schedule** column, click the schedule. This opens the **Scheduled backups** page for the index.
For each schedule, the page shows the frequency, retention period, and next scheduled run time. From here, you can:
* **Pause or resume a schedule**: Use the toggle on the schedule. An index can have up to three schedules, but only one can be enabled at a time.
* **Edit a schedule**: Expand the schedule, change the **Frequency** or **Retention**, and click **Update**.
* **Delete a schedule**: Select **Delete** from the actions menu of the schedule.
The scheduled backups API requires `X-Pinecone-API-Version: unstable`.
You can [list schedules](/reference/api/2026-04/control-plane/list_backup_schedules), [update a schedule](/reference/api/2026-04/control-plane/update_backup_schedule) (e.g., to pause it or change the frequency), [delete a schedule](/reference/api/2026-04/control-plane/delete_backup_schedule), and [view the backup history](/reference/api/2026-04/control-plane/list_backup_schedule_history) for a schedule.
Deleting a schedule does not delete any backups that were previously created by it. For more details, see [Scheduled backups](/guides/manage-data/backups-overview#scheduled-backups).
# Backups overview
Source: https://docs.pinecone.io/guides/manage-data/backups-overview
Learn how serverless index backups work in Pinecone, including scheduled backups, retention policies, and use cases for restoring or copying data.
A backup is a static copy of a serverless [index](/guides/index-data/indexing-overview) that only consumes storage. It is a non-queryable representation of a set of records. You can [create a backup](/guides/manage-data/back-up-an-index) of a serverless index, and you can [create a new serverless index from a backup](/guides/manage-data/restore-an-index). This allows you to restore the index with the same or different configurations.
## Use cases
Creating a backup is useful when performing tasks like the following:
* Protecting an index from manual or system failures.
* Temporarily shutting down an index.
* Copying the data from one index into a different index.
* Making a backup of your index.
* Experimenting with different index configurations.
## Scheduled backups
Instead of creating backups manually, you can define a recurring backup schedule that runs automatically. Each schedule includes:
* **Frequency**: Backups can run daily, weekly, or monthly.
* **Retention**: A required expiration policy that automatically deletes old backups, keeping storage costs predictable.
Each index supports one active schedule at a time. Backups created by a schedule are automatically named `{name}-{ISO8601_timestamp}`.
You can create and manage backup schedules in the [Pinecone console](https://app.pinecone.io/organizations/-/projects/-/backups) or with the API. For step-by-step instructions, see [Schedule automated backups](/guides/manage-data/back-up-an-index#schedule-automated-backups).
The scheduled backups API requires `X-Pinecone-API-Version: unstable`.
For example, to create a daily backup that expires after 7 days:
```bash theme={null}
curl -sS -X POST "https://api.pinecone.io/indexes/${INDEX_NAME}/backup-schedules" \
-H "api-key: ${PINECONE_API_KEY}" \
-H "X-Pinecone-API-Version: unstable" \
-H "Content-Type: application/json" \
-d '{
"name": "my-nightly-backup",
"schedule": {
"type": "time-based",
"frequency": "daily"
},
"retention": {
"expire_after_days": 7
}
}'
```
Deleting a schedule does not delete any backups that were previously created by it. If you delete an index, all associated schedules are automatically deleted.
For more details, see the API reference:
* [Create backup schedule](/reference/api/2026-04/control-plane/create_backup_schedule)
* [List backup schedules](/reference/api/2026-04/control-plane/list_backup_schedules)
* [Describe backup schedule](/reference/api/2026-04/control-plane/describe_backup_schedule)
* [Update backup schedule](/reference/api/2026-04/control-plane/update_backup_schedule)
* [Delete backup schedule](/reference/api/2026-04/control-plane/delete_backup_schedule)
* [List schedule history](/reference/api/2026-04/control-plane/list_backup_schedule_history)
## Performance
Backup and restore times depend upon the size of the index and number of namespaces:
* For less than 1M vectors in a namespace, backups and restores take approximately 10 minutes.
* For 100,000,000 vectors, backups and restores can take up to 5 hours.
## Quotas
| Metric | Starter plan | Builder plan | Standard plan | Enterprise plan |
| :------------------ | :----------- | :----------- | :------------ | :-------------- |
| Backups per project | N/A | N/A | 500 | 1000 |
Backups are not available on the Starter or Builder plans. To create backups, [upgrade to the Standard or Enterprise plan](/guides/organizations/manage-billing/upgrade-billing-plan).
## Limitations
Backup limitations are as follows:
* Backups are stored in the same project, cloud provider, and region as the source index.
* You can only restore an index to the same project and cloud provider as the source index. Restoring to a different region on the same cloud provider is supported using the `unstable` API version. For details, see [Restore to a different region](/guides/manage-data/restore-an-index#restore-to-a-different-region).
* Backups only include vectors that were in the index at least 15 minutes prior to the backup time. This means that if a vector was inserted into an index and a backup was immediately taken after, the recently inserted vector may not be backed up. More specifically, if a backup is created only a few minutes after the source index was created, the backup may have 0 vectors.
* You can only perform operations on backups in the current Pinecone project.
* Backups are supported for indexes without a schema definition and for integrated embedding indexes that use the records API. They are not supported for full-text search indexes with document schemas that include `full_text_search` string fields, `dense_vector` fields, or `sparse_vector` fields. Indexes with document schemas also do not support `semantic_text` fields.
## Backup and restore cost
* To understand how cost is calculated for backups and restores, see [Understanding cost](/guides/manage-cost/understanding-cost#backups-and-restores).
* For up-to-date pricing information, see [Pricing](https://www.pinecone.io/pricing/).
# Delete records
Source: https://docs.pinecone.io/guides/manage-data/delete-data
Delete records from a Pinecone index namespace by ID or metadata filter, including delete-by-ID, delete-all, and delete-by-metadata operations.
This page shows you how to [delete](/reference/api/latest/data-plane/delete) records from an index [namespace](/guides/index-data/indexing-overview#namespaces).
Deletes consume [write units (WUs)](/guides/manage-cost/understanding-cost#write-units). See [Understanding cost](/guides/manage-cost/understanding-cost#delete) for how delete cost is calculated.
## Delete records by ID
Since Pinecone records can always be efficiently accessed using their ID, deleting by ID is the most efficient way to remove specific records from a namespace.
To remove records from the default namespace, specify `"__default__"` as the namespace in your request.
```Python Python theme={null}
# pip install "pinecone[grpc]"
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
index = pc.Index(host="INDEX_HOST")
index.delete(ids=["id-1", "id-2"], namespace='example-namespace')
```
```JavaScript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({ apiKey: "YOUR_API_KEY" })
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
const index = pc.index("INDEX_NAME", "INDEX_HOST")
const ns = index.namespace('example-namespace')
// Delete one record by ID.
await ns.deleteOne('id-1');
// Delete more than one record by ID.
await ns.deleteMany(['id-2', 'id-3']);
```
```java Java theme={null}
import io.pinecone.clients.Index;
import io.pinecone.configs.PineconeConfig;
import io.pinecone.configs.PineconeConnection;
import java.util.Arrays;
import java.util.List;
public class DeleteExample {
public static void main(String[] args) {
PineconeConfig config = new PineconeConfig("YOUR_API_KEY");
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
config.setHost("INDEX_HOST");
PineconeConnection connection = new PineconeConnection(config);
Index index = new Index(connection, "INDEX_NAME");
List ids = Arrays.asList("id-1", "id-2");
index.deleteByIds(ids, "example-namespace");
}
}
```
```go Go theme={null}
package main
import (
"context"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
idxConnection, err := pc.Index(pinecone.NewIndexConnParams{Host: "INDEX_HOST", Namespace: "example-namespace"})
if err != nil {
log.Fatalf("Failed to create IndexConnection for Host: %v", err)
}
id1 := "id-1"
id2 := "id-2"
err = idxConnection.DeleteVectorsById(ctx, []string{id1, id2})
if err != nil {
log.Fatalf("Failed to delete vector with ID %v: %v", id, err)
}
}
```
```bash curl theme={null}
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
curl "https://$INDEX_HOST/vectors/delete" \
-H "Api-Key: $PINECONE_API_KEY" \
-H 'Content-Type: application/json' \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"ids": [
"id-1",
"id-2"
],
"namespace": "example-namespace"
}
'
```
## Delete records by metadata
To delete records from a namespace based on their metadata values, pass a [metadata filter expression](/guides/index-data/indexing-overview#metadata-filter-expressions) to the `delete` operation. This deletes all records in the namespace that match the filter expression.
For example, the following code deletes all records with a `genre` field set to `documentary` from namespace `example-namespace`:
```Python Python theme={null}
# pip install "pinecone[grpc]"
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
index = pc.Index(host="INDEX_HOST")
index.delete(
filter={
"genre": {"$eq": "documentary"}
},
namespace="example-namespace"
)
```
```JavaScript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({ apiKey: "YOUR_API_KEY" })
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
const index = pc.index("INDEX_NAME", "INDEX_HOST")
const ns = index.namespace('example-namespace')
await ns.deleteMany({
genre: { $eq: "documentary" },
});
```
```java Java theme={null}
import com.google.protobuf.Struct;
import com.google.protobuf.Value;
import io.pinecone.clients.Index;
import io.pinecone.configs.PineconeConfig;
import io.pinecone.configs.PineconeConnection;
import java.util.Arrays;
import java.util.List;
public class DeleteExample {
public static void main(String[] args) {
PineconeConfig config = new PineconeConfig("YOUR_API_KEY");
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
config.setHost("INDEX_HOST");
PineconeConnection connection = new PineconeConnection(config);
Index index = new Index(connection, "INDEX_NAME");
Struct filter = Struct.newBuilder()
.putFields("genre", Value.newBuilder()
.setStructValue(Struct.newBuilder()
.putFields("$eq", Value.newBuilder()
.setStringValue("documentary")
.build()))
.build())
.build();
index.deleteByFilter(filter, "example-namespace");
}
}
```
```go Go theme={null}
package main
import (
"context"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
idxConnection, err := pc.Index(pinecone.NewIndexConnParams{Host: "INDEX_HOST", Namespace: "example-namespace"})
if err != nil {
log.Fatalf("Failed to create IndexConnection for Host: %v", err)
}
metadataFilter := map[string]interface{}{
"genre": map[string]interface{}{
"$eq": "documentary",
},
}
filter, err := structpb.NewStruct(metadataFilter)
if err != nil {
log.Fatalf("Failed to create metadata filter: %v", err)
}
err = idxConnection.DeleteVectorsByFilter(ctx, filter)
if err != nil {
log.Fatalf("Failed to delete vector(s) with filter %+v: %v", filter, err)
}
}
```
```bash curl theme={null}
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
curl -i "https://$INDEX_HOST/vectors/delete" \
-H 'Api-Key: $PINECONE_API_KEY' \
-H 'Content-Type: application/json' \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"filter": {"genre": {"$eq": "documentary"}},
"namespace": "example-namespace"
}'
```
## Delete all records in a namespace
To delete all of the records in a namespace but not the namespace itself, provide a `namespace` parameter and specify the appropriate `deleteAll` parameter for your SDK. To target the default namespace, set `namespace` to `"__default__"`.
```Python Python theme={null}
# pip install "pinecone[grpc]"
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
index = pc.Index(host="INDEX_HOST")
index.delete(delete_all=True, namespace='example-namespace')
```
```JavaScript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({ apiKey: "YOUR_API_KEY" })
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
const index = pc.index("INDEX_NAME", "INDEX_HOST")
await index.namespace('example-namespace').deleteAll();
```
```java Java theme={null}
import io.pinecone.clients.Index;
import io.pinecone.configs.PineconeConfig;
import io.pinecone.configs.PineconeConnection;
import java.util.Arrays;
import java.util.List;
public class DeleteExample {
public static void main(String[] args) {
PineconeConfig config = new PineconeConfig("YOUR_API_KEY");
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
config.setHost("INDEX_HOST");
PineconeConnection connection = new PineconeConnection(config);
Index index = new Index(connection, "INDEX_NAME");
index.deleteAll("example-namespace");
}
}
```
```go Go theme={null}
package main
import (
"context"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
idxConnection, err := pc.Index(pinecone.NewIndexConnParams{Host: "INDEX_HOST", Namespace: "example-namespace"})
if err != nil {
log.Fatalf("Failed to create IndexConnection for Host: %v", err)
}
err = idxConnection.DeleteAllVectorsInNamespace(ctx)
if err != nil {
log.Fatalf("Failed to delete all vectors in namespace %v: %v", namespace, err)
}
}
```
```bash curl theme={null}
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
curl "https://$INDEX_HOST/vectors/delete" \
-H "Api-Key: $PINECONE_API_KEY" \
-H 'Content-Type: application/json' \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"deleteAll": true,
"namespace": "example-namespace"
}
'
```
## Delete an entire namespace
To delete an entire namespace and all of its records, see [Delete a namespace](/guides/manage-data/manage-namespaces#delete-a-namespace).
## Delete an entire index
To remove all records from an index, [delete the index](/guides/manage-data/manage-indexes#delete-an-index) and [recreate it](/guides/index-data/create-an-index).
## Delete limits
**Delete by ID limits:**
| Metric | Limit |
| :------------------ | :--------------------------------------------- |
| Max IDs per request | 1000 IDs |
| Max request rate | 5000 records per second per index or namespace |
**Delete by metadata limits:**
| Metric | Limit |
| :--------------- | :------------------------------------------------------------------------- |
| Max request rate | 5 requests per second per namespace 500 requests per second per index |
## Data freshness
Pinecone is eventually consistent, so there can be a slight delay before new or changed records are visible to queries. You can view index stats to [check data freshness](/guides/index-data/check-data-freshness).
# Fetch records
Source: https://docs.pinecone.io/guides/manage-data/fetch-data
Retrieve full Pinecone records by ID from a namespace to inspect vector values, metadata, and IDs, or verify upserts using the fetch operation.
You can fetch data using the [Pinecone console](https://app.pinecone.io/organizations/-/projects/-/indexes/-/browser).
Fetches consume [read units (RUs)](/guides/manage-cost/understanding-cost#read-units). See [Understanding cost](/guides/manage-cost/understanding-cost#fetch) for how fetch cost is calculated.
## Fetch records by ID
To fetch records from a namespace based on their IDs, use the `fetch` operation with the following parameters:
* `namespace`: The [namespace](/guides/index-data/indexing-overview#namespaces) containing the records to fetch. To use the default namespace, set this to `"__default__"`.
* `ids`: The IDs of the records to fetch. Maximum of 1000.
For on-demand indexes, since vector values are retrieved from object storage, fetch operations may have increased latency. If you only need metadata or IDs, consider using the [`query`](/reference/api/latest/data-plane/query) operation with `include_values` set to `false` instead. See [Decrease latency](/guides/optimize/decrease-latency#avoid-including-vector-values-when-not-needed) for more details.
```Python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
index = pc.Index(host="INDEX_HOST")
index.fetch(ids=["id-1", "id-2"], namespace="example-namespace")
```
```JavaScript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({ apiKey: "YOUR_API_KEY" })
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
const index = pc.index("INDEX_NAME", "INDEX_HOST")
const fetchResult = await index.namespace('example-namespace').fetch(['id-1', 'id-2']);
```
```java Java theme={null}
import io.pinecone.clients.Index;
import io.pinecone.configs.PineconeConfig;
import io.pinecone.configs.PineconeConnection;
import io.pinecone.proto.FetchResponse;
import java.util.Arrays;
import java.util.List;
public class FetchExample {
public static void main(String[] args) {
PineconeConfig config = new PineconeConfig("YOUR_API_KEY");
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
config.setHost("INDEX_HOST");
PineconeConnection connection = new PineconeConnection(config);
Index index = new Index(connection, "INDEX_NAME");
List ids = Arrays.asList("id-1", "id-2");
FetchResponse fetchResponse = index.fetch(ids, "example-namespace");
System.out.println(fetchResponse);
}
}
```
```go Go theme={null}
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func prettifyStruct(obj interface{}) string {
bytes, _ := json.MarshalIndent(obj, "", " ")
return string(bytes)
}
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
idxConnection, err := pc.Index(pinecone.NewIndexConnParams{Host: "INDEX_HOST", Namespace: "example-namespace"})
if err != nil {
log.Fatalf("Failed to create IndexConnection for Host: %v", err)
}
res, err := idxConnection.FetchVectors(ctx, []string{"id-1", "id-2"})
if err != nil {
log.Fatalf("Failed to fetch vectors: %v", err)
} else {
fmt.Printf(prettifyStruct(res))
}
}
```
```bash curl theme={null}
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
curl -X GET "https://$INDEX_HOST/vectors/fetch?ids=id-1&ids=id-2&namespace=example-namespace" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10"
```
The response looks like this:
```Python Python theme={null}
{'namespace': 'example-namespace',
'usage': {'readUnits': 1},
'vectors': {'id-1': {'id': 'id-1',
'values': [0.568879, 0.632687092, 0.856837332, ...]},
'id-2': {'id': 'id-2',
'values': [0.00891787093, 0.581895, 0.315718859, ...]}}}
```
```JavaScript JavaScript theme={null}
{'namespace': 'example-namespace',
'usage': {'readUnits': 1},
'records': {'id-1': {'id': 'id-1',
'values': [0.568879, 0.632687092, 0.856837332, ...]},
'id-2': {'id': 'id-2',
'values': [0.00891787093, 0.581895, 0.315718859, ...]}}}
```
```java Java theme={null}
namespace: "example-namespace"
vectors {
key: "id-1"
value {
id: "id-1"
values: 0.568879
values: 0.632687092
values: 0.856837332
...
}
}
vectors {
key: "id-2"
value {
id: "id-2"
values: 0.00891787093
values: 0.581895
values: 0.315718859
...
}
}
usage {
read_units: 1
}
```
```go Go theme={null}
{
"vectors": {
"id-1": {
"id": "id-1",
"values": [
-0.0089730695,
-0.020010853,
-0.0042787646,
...
]
},
"id-2": {
"id": "id-2",
"values": [
-0.005380766,
0.00215196,
-0.014833462,
...
]
}
},
"usage": {
"read_units": 1
}
}
```
```json curl theme={null}
{
"vectors": {
"id-1": {
"id": "id-1",
"values": [0.568879, 0.632687092, 0.856837332, ...]
},
"id-2": {
"id": "id-2",
"values": [0.00891787093, 0.581895, 0.315718859, ...]
}
},
"namespace": "example-namespace",
"usage": {"readUnits": 1},
}
```
## Fetch records by metadata
To fetch records from a namespace based on their metadata values, use the `fetch_by_metadata` operation with the following parameters:
| Parameter | Required | Description |
| :---------------- | :------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `filter` | Yes | A [metadata filter expression](/guides/index-data/indexing-overview#metadata-filter-expressions) describing the records to fetch. Must be present and non-empty. |
| `limit` | No | The maximum number of matching records to return in a single response. Defaults to 100; maximum 10,000. To retrieve more than 10,000 matching records, paginate using `paginationToken`. |
| `namespace` | No | The [namespace](/guides/index-data/indexing-overview#namespaces) containing the records to fetch. If omitted or set to an empty string, defaults to the default namespace. To explicitly use the default namespace, set this to `"__default__"`. |
| `paginationToken` | No | The `next` token value from the `pagination` object found in a previous response. Include this value to fetch the next page of results, or omit it to start from the beginning. Must be used with the same `namespace` and `filter` parameters that generated it — using an existing token with different parameters will return incorrect results. |
For example, the following code fetches 2 records with a `genre` field set to `Action/Adventure` from the default namespace:
```Python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
index = pc.Index(host="INDEX_HOST")
results = index.fetch_by_metadata(
filter={"genre": {"$eq": "Action/Adventure"}},
namespace="__default__",
limit=2
)
print(results)
```
```JavaScript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({ apiKey: "YOUR_API_KEY" })
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
const index = pc.index("INDEX_NAME", "INDEX_HOST")
const results = await index.fetchByMetadata({
filter: { genre: { $eq: 'Action/Adventure' } },
namespace: '__default__',
limit: 2
});
console.log(results);
```
```java Java theme={null}
import com.google.protobuf.Struct;
import com.google.protobuf.Value;
import io.pinecone.clients.Index;
import io.pinecone.configs.PineconeConfig;
import io.pinecone.configs.PineconeConnection;
import io.pinecone.proto.FetchByMetadataResponse;
public class FetchByMetadataExample {
public static void main(String[] args) {
PineconeConfig config = new PineconeConfig("YOUR_API_KEY");
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
config.setHost("INDEX_HOST");
PineconeConnection connection = new PineconeConnection(config);
Index index = new Index(connection, "INDEX_NAME");
Struct filter = Struct.newBuilder()
.putFields("genre", Value.newBuilder()
.setStructValue(Struct.newBuilder()
.putFields("$eq", Value.newBuilder()
.setStringValue("Action/Adventure")
.build())
.build())
.build())
.build();
FetchByMetadataResponse response = index.fetchByMetadata(
"__default__", filter, 2, null);
System.out.println(response);
}
}
```
```go Go theme={null}
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
"google.golang.org/protobuf/types/known/structpb"
)
func prettifyStruct(obj interface{}) string {
bytes, _ := json.MarshalIndent(obj, "", " ")
return string(bytes)
}
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
idxConnection, err := pc.Index(pinecone.NewIndexConnParams{Host: "INDEX_HOST"})
if err != nil {
log.Fatalf("Failed to create IndexConnection for Host: %v", err)
}
filter, err := structpb.NewStruct(map[string]interface{}{
"genre": map[string]interface{}{
"$eq": "Action/Adventure",
},
})
if err != nil {
log.Fatalf("Failed to create filter: %v", err)
}
namespace := "__default__"
limit := uint32(2)
res, err := idxConnection.FetchVectorsByMetadata(ctx, &pinecone.FetchVectorsByMetadataRequest{
Filter: filter,
Namespace: &namespace,
Limit: &limit,
})
if err != nil {
log.Fatalf("Failed to fetch vectors by metadata: %v", err)
}
fmt.Printf(prettifyStruct(res))
}
```
```shell curl theme={null}
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
curl -X POST "https://$INDEX_HOST/vectors/fetch_by_metadata" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "Content-Type: application/json" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"namespace": "__default__",
"filter": {"genre": {"$eq": "Action/Adventure"}},
"limit": 2
}'
```
The response looks like this:
```json theme={null}
{
"vectors": {
"0": {
"id": "0",
"values": [
0.0234527588, 0.0291595459 ...
],
"metadata": {
"box-office": 2923706026,
"genre": "Action/Adventure",
"summary": "On the alien world of Pandora, paraplegic Marine Jake Sully uses an avatar to walk again and becomes torn between his mission and protecting the planet's indigenous Na'vi people. The film stars Sam Worthington, Zoe Saldana, and Sigourney Weaver.",
"title": "Avatar",
"year": 2009
}
},
"1": {
"id": "1",
"values": [
0.0397644043, 0.013053894, ...
],
"metadata": {
"box-office": 2799439100,
"genre": "Action/Adventure",
"summary": "In the aftermath of Thanos wiping out half of the universe, the remaining Avengers assemble once more to undo the chaos, leading to a time-traveling adventure. Stars Robert Downey Jr., Chris Evans, and Scarlett Johansson.",
"title": "Avengers: Endgame",
"year": 2019
}
}
},
"namespace": "__default__",
"usage": {
"readUnits": 1
},
"pagination": {
"next": "Tm90aGluZyB0byBzZWUgaGVyZQo="
}
}
```
To fetch the next page of results, pass the pagination token from the previous response. For example:
```Python Python theme={null}
next_results = index.fetch_by_metadata(
filter={"genre": {"$eq": "Action/Adventure"}},
namespace="__default__",
limit=2,
pagination_token="Tm90aGluZyB0byBzZWUgaGVyZQo="
)
```
```JavaScript JavaScript theme={null}
const nextResults = await index.fetchByMetadata({
filter: { genre: { $eq: 'Action/Adventure' } },
namespace: '__default__',
limit: 2,
paginationToken: 'Tm90aGluZyB0byBzZWUgaGVyZQo='
});
```
```java Java theme={null}
FetchByMetadataResponse nextPage = index.fetchByMetadata(
"__default__", filter, 2, "Tm90aGluZyB0byBzZWUgaGVyZQo=");
```
```go Go theme={null}
paginationToken := "Tm90aGluZyB0byBzZWUgaGVyZQo="
nextRes, err := idxConnection.FetchVectorsByMetadata(ctx, &pinecone.FetchVectorsByMetadataRequest{
Filter: filter,
Namespace: &namespace,
Limit: &limit,
PaginationToken: &paginationToken,
})
```
```shell curl theme={null}
curl -X POST "https://$INDEX_HOST/vectors/fetch_by_metadata" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "Content-Type: application/json" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"namespace": "__default__",
"filter": {"genre": {"$eq": "Action/Adventure"}},
"limit": 2,
"paginationToken": "Tm90aGluZyB0byBzZWUgaGVyZQo="
}'
```
When there are more results available, the response includes a `pagination` object with a `next` token. When there are no more results, the response does not include a `pagination` object.
## Fetch limits
**Fetch by ID limits:**
| Metric | Limit |
| :------------------ | :-------------------------------- |
| Max IDs per request | 1000 IDs |
| Max request size | N/A |
| Max request rate | 100 requests per second per index |
**Fetch by metadata limits:**
| Metric | Limit |
| :----------------------- | :---------------------------------- |
| Max records per response | 10,000 records |
| Max response size | 4 MB |
| Max request rate | 5 requests per second per namespace |
To retrieve more than 10,000 matching records, paginate through results using the `paginationToken` parameter. See [Fetch records by metadata](#fetch-records-by-metadata).
## Data freshness
Pinecone is eventually consistent, so there can be a slight delay before new or changed records are visible to queries. You can view index stats to [check data freshness](/guides/index-data/check-data-freshness).
# List record IDs
Source: https://docs.pinecone.io/guides/manage-data/list-record-ids
List the IDs of records in a Pinecone serverless namespace, filter by ID prefix, and paginate results to verify upserts cheaply and quickly.
You can list the IDs of all records in a [namespace](/guides/index-data/indexing-overview#namespaces) or just the records with a common ID prefix.
Using `list` to get record IDs and not the associated data is a cheap and fast way to check [upserts](/guides/index-data/upsert-data).
The `list` endpoint is supported only for serverless indexes.
## List the IDs of all records in a namespace
To list the IDs of all records in the namespace of a serverless index, pass only the `namespace` parameter:
```python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key='YOUR_API_KEY')
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
index = pc.Index(host="INDEX_HOST")
for ids in index.list(namespace='example-namespace'):
print(ids)
# Response:
# ['doc1#chunk1', 'doc1#chunk2', 'doc1#chunk3']
```
```js JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const pc = new Pinecone();
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
const index = pc.index("INDEX_NAME", "INDEX_HOST").namespace("example-namespace");
const results = await index.listPaginated();
console.log(results);
// {
// vectors: [
// { id: 'doc1#01' }, { id: 'doc1#02' }, { id: 'doc1#03' },
// { id: 'doc1#04' }, { id: 'doc1#05' }, { id: 'doc1#06' },
// { id: 'doc1#07' }, { id: 'doc1#08' }, { id: 'doc1#09' },
// ...
// ],
// pagination: {
// next: 'eyJza2lwX3Bhc3QiOiJwcmVUZXN0LS04MCIsInByZWZpeCI6InByZVRlc3QifQ=='
// },
// namespace: 'example-namespace',
// usage: { readUnits: 1 }
// }
// Fetch the next page of results
await index.listPaginated({ prefix: 'doc1#', paginationToken: results.pagination.next});
```
```java Java theme={null}
import io.pinecone.clients.Index;
import io.pinecone.configs.PineconeConfig;
import io.pinecone.configs.PineconeConnection;
import io.pinecone.proto.ListResponse;
public class ListExample {
public static void main(String[] args) {
PineconeConfig config = new PineconeConfig("YOUR_API_KEY");
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
config.setHost("INDEX_HOST");
PineconeConnection connection = new PineconeConnection(config);
Index index = new Index(connection, "INDEX_NAME");
// get the pagination token
String paginationToken = index.list("example-namespace", 3).getPagination().getNext();
// get vectors with limit 3 with the paginationToken obtained from the previous step
ListResponse listResponse = index.list("example-namespace", 3, paginationToken);
}
}
// Response:
// vectors {
// id: "doc1#chunk1"
// }
// vectors {
// id: "doc1#chunk2"
// }
// vectors {
// id: "doc2#chunk1"
// }
// vectors {
// id: "doc3#chunk1"
// }
// pagination {
// next: "eyJza2lwX3Bhc3QiOiJhbHN0cm9lbWVyaWEtcGVydXZpYW4iLCJwcmVmaXgiOm51bGx9"
// }
// namespace: "example-namespace"
// usage {
// read_units: 1
// }
```
```go Go theme={null}
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func prettifyStruct(obj interface{}) string {
bytes, _ := json.MarshalIndent(obj, "", " ")
return string(bytes)
}
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
idxConnection, err := pc.Index(pinecone.NewIndexConnParams{Host: "INDEX_HOST", Namespace: "example-namespace"})
if err != nil {
log.Fatalf("Failed to create IndexConnection for Host: %v", err)
}
limit := uint32(3)
res, err := idxConnection.ListVectors(ctx, &pinecone.ListVectorsRequest{
Limit: &limit,
})
if len(res.VectorIds) == 0 {
fmt.Println("No vectors found")
} else {
fmt.Printf(prettifyStruct(res))
}
}
// Response:
// {
// "vector_ids": [
// "doc1#chunk1",
// "doc1#chunk2",
// "doc1#chunk3"
// ],
// "usage": {
// "read_units": 1
// },
// "next_pagination_token": "eyJza2lwX3Bhc3QiOiIwMDBkMTc4OC0zMDAxLTQwZmMtYjZjNC0wOWI2N2I5N2JjNDUiLCJwcmVmaXgiOm51bGx9"
// }
```
```shell curl theme={null}
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
curl -X GET "https://$INDEX_HOST/vectors/list?namespace=example-namespace" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10"
# Response:
# {
# "vectors": [
# { "id": "doc1#chunk1" },
# { "id": "doc1#chunk2" },
# { "id": "doc1#chunk3" },
# { "id": "doc1#chunk4" },
# ...
# ],
# "pagination": {
# "next": "c2Vjb25kY2FsbA=="
# },
# "namespace": "example-namespace",
# "usage": {
# "readUnits": 1
# }
# }
```
## List the IDs of records with a common prefix
ID prefixes enable you to query segments of content. Use the `list` endpoint to list all of the records with the common prefix. For more details, see [Use structured IDs](/guides/index-data/data-modeling#use-structured-ids).
## Paginate through results
The `list` endpoint returns up to 100 IDs per page at a time by default. If the `limit` parameter is passed, `list` returns up to that number of IDs per page instead. For example, if `limit=3`, up to 3 IDs be returned per page. Whenever there are additional IDs to return, the response also includes a `pagination_token` for fetching the next page of IDs.
### Implicit pagination
When using the Python SDK, `list` paginates automatically.
```python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key='YOUR_API_KEY')
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
index = pc.Index(host="INDEX_HOST")
for ids in index.list(namespace='example-namespace'):
print(ids)
# Response:
# ['doc1#chunk1', 'doc1#chunk2', 'doc1#chunk3']
# ['doc1#chunk4', 'doc1#chunk5', 'doc1#chunk6']
# ...
```
### Manual pagination
When using the Node.js SDK, Java SDK, Go SDK, or REST API, you must manually fetch each page of results. You can also manually paginate with the Python SDK using `list_paginated()`.
```python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key='YOUR_API_KEY')
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
index = pc.Index(host="INDEX_HOST")
namespace = 'example-namespace'
# For manual control over pagination
results = index.list_paginated(
prefix='pref',
limit=3,
namespace='example-namespace'
)
print(results.namespace)
print([v.id for v in results.vectors])
print(results.pagination.next)
print(results.usage)
# Results:
# ['10103-0', '10103-1', '10103-10']
# eyJza2lwX3Bhc3QiOiIxMDEwMy0=
# {'read_units': 1}
```
```js JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const pc = new Pinecone();
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
const index = pc.index("INDEX_NAME", "INDEX_HOST").namespace("example-namespace");
const results = await index.listPaginated({ prefix: 'doc1#', limit: 3 });
console.log(results);
// Response:
// {
// vectors: [
// { id: 'doc1#01' }, { id: 'doc1#02' }, { id: 'doc1#03' }
// ],
// pagination: {
// next: 'eyJza2lwX3Bhc3QiOiJwcmVUZXN0LSCIsInByZWZpeCI6InByZVRlc3QifQ=='
// },
// namespace: 'example-namespace',
// usage: { readUnits: 1 }
// }
```
```java Java theme={null}
import io.pinecone.clients.Index;
import io.pinecone.configs.PineconeConfig;
import io.pinecone.configs.PineconeConnection;
import io.pinecone.proto.ListResponse;
public class ListExample {
public static void main(String[] args) {
PineconeConfig config = new PineconeConfig("YOUR_API_KEY");
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
config.setHost("INDEX_HOST");
PineconeConnection connection = new PineconeConnection(config);
Index index = new Index(connection, "INDEX_NAME");
ListResponse listResponse = index.list("example-namespace", "doc1#" 2); /* Note: You must include an ID prefix to list vector IDs. */
System.out.println(listResponse.getVectorsList());
System.out.println(listResponse.getPagination());
}
}
// Response:
// vectors {
// id: "doc1#chunk1"
// }
// vectors {
// id: "doc1#chunk2"
// }
// pagination {
// next: "eyJza2lwX3Bhc3QiOiJhbHN0cm9lbWVyaWEtcGVydXZpYW4iLCJwcmVmaXgiOm51bGx9"
// }
// namespace: "example-namespace"
// usage {
// read_units: 1
// }
```
```go Go theme={null}
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func prettifyStruct(obj interface{}) string {
bytes, _ := json.MarshalIndent(obj, "", " ")
return string(bytes)
}
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
idxConnection, err := pc.Index(pinecone.NewIndexConnParams{Host: "INDEX_HOST", Namespace: "example-namespace"})
if err != nil {
log.Fatalf("Failed to create IndexConnection for Host: %v", err)
}
limit := uint32(3)
res, err := idxConnection.ListVectors(ctx, &pinecone.ListVectorsRequest{
Limit: &limit,
})
if len(res.VectorIds) == 0 {
fmt.Println("No vectors found")
} else {
fmt.Printf(prettifyStruct(res))
}
}
// Response:
// {
// "vector_ids": [
// "doc1#chunk1",
// "doc1#chunk2",
// "doc1#chunk3"
// ],
// "usage": {
// "read_units": 1
// },
// "next_pagination_token": "eyJza2lwX3Bhc3QiOiIwMDBkMTc4OC0zMDAxLTQwZmMtYjZjNC0wOWI2N2I5N2JjNDUiLCJwcmVmaXgiOm51bGx9"
// }
```
```shell curl theme={null}
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
curl -X GET "https://$INDEX_HOST/vectors/list?namespace=example-namespace" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10"
# Response:
# {
# "vectors": [
# { "id": "doc1#chunk1" },
# { "id": "doc1#chunk2" },
# { "id": "doc1#chunk3" },
# { "id": "doc1#chunk4" },
# ...
# ],
# "pagination": {
# "next": "c2Vjb25kY2FsbA=="
# },
# "namespace": "example-namespace",
# "usage": {
# "readUnits": 1
# }
# }
```
Then, to get the next batch of IDs, use the returned `pagination_token`:
```python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key='YOUR_API_KEY')
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
index = pc.Index(host="INDEX_HOST")
namespace = 'example-namespace'
results = index.list_paginated(
prefix='pref',
limit=3,
namespace='example-namespace',
pagination_token='eyJza2lwX3Bhc3QiOiIxMDEwMy0='
)
print(results.namespace)
print([v.id for v in results.vectors])
print(results.pagination.next)
print(results.usage)
# Response:
# ['10103-0', '10103-1', '10103-10']
# xndlsInByZWZpeCI6IjEwMTAzIn0==
# {'read_units': 1}
```
```js JavaScript theme={null}
await index.listPaginated({ prefix: 'doc1#', limit: 3, paginationToken: results.pagination.next});
// Response:
// {
// vectors: [
// { id: 'doc1#10' }, { id: 'doc1#11' }, { id: 'doc1#12' }
// ],
// pagination: {
// next: 'dfajlkjfdsoijeowjoDJFKLJldLIFf34KFNLDSndaklqoLQJORN45afdlkJ=='
// },
// namespace: 'example-namespace',
// usage: { readUnits: 1 }
// }
```
```java Java theme={null}
listResponse = index.list("example-namespace", "doc1#", "eyJza2lwX3Bhc3QiOiJ2MTg4IiwicHJlZml4IjpudWxsfQ==");
System.out.println(listResponse.getVectorsList());
// Response:
// vectors {
// id: "doc1#chunk3"
// }
// vectors {
// id: "doc1#chunk4"
// }
// vectors {
// id: "doc1#chunk5"
// }
// vectors {
// id: "doc1#chunk6"
// }
// vectors {
// id: "doc1#chunk7"
// }
// vectors {
// id: "doc1#chunk8"
// }
// pagination {
// next: "eyJza2lwX3Bhc3QiOiJhbHN0cm9lbWVyaWEtcGVydXZpYW4iLCJwcmVmaXgiOm51bGx9"
// }
// namespace: "example-namespace"
// usage {
// read_units: 1
// }
```
```go Go theme={null}
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func prettifyStruct(obj interface{}) string {
bytes, _ := json.MarshalIndent(obj, "", " ")
return string(bytes)
}
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
idxConnection, err := pc.Index(pinecone.NewIndexConnParams{Host: "INDEX_HOST", Namespace: "example-namespace"})
if err != nil {
log.Fatalf("Failed to create IndexConnection for Host: %v", err)
}
limit := uint32(3)
paginationToken := "dfajlkjfdsoijeowjoDJFKLJldLIFf34KFNLDSndaklqoLQJORN45afdlkJ=="
res, err := idxConnection.ListVectors(ctx, &pinecone.ListVectorsRequest{
Limit: &limit,
PaginationToken: &paginationToken,
})
if len(res.VectorIds) == 0 {
fmt.Println("No vectors found")
} else {
fmt.Printf(prettifyStruct(res))
}
}
// Response:
// {
// "vector_ids": [
// "doc1#chunk4",
// "doc1#chunk5",
// "doc1#chunk6"
// ],
// "usage": {
// "read_units": 1
// },
// "next_pagination_token": "eyJza2lwX3Bhc3QiOiIwMDBkMTc4OC0zMDAxLTQwZmMtYjZjNC0wOWI2N2I5N2JjNDUiLCJwcmVmaXgiOm51bGx9"
// }
```
```shell curl theme={null}
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
curl -X GET "https://$INDEX_HOST/vectors/list?namespace=example-namespace&paginationToken=c2Vjb25kY2FsbA%3D%3D" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10"
# Response:
# {
# "vectors": [
# { "id": "doc2#chunk1" },
# { "id": "doc2#chunk1" },
# { "id": "doc2#chunk1" },
# { "id": "doc2#chunk1" },
# ...
# ],
# "pagination": {
# "next": "mn23b4jB3Y9jpsS1"
# },
# "namespace": "example-namespace",
# "usage": {
# "readUnits": 1
# }
# }
```
When there are no more IDs to return, the response does not includes a `pagination_token`:
```python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key='YOUR_API_KEY')
index = pc.Index(host="INDEX_HOST")
namespace = 'example-namespace'
results = index.list_paginated(
prefix='10103',
limit=3,
pagination_token='xndlsInByZWZpeCI6IjEwMTAzIn0=='
)
print(results.namespace)
print([v.id for v in results.vectors])
print(results.pagination.next)
print(results.usage)
# Response:
# ['10103-4', '10103-5', '10103-6']
# {'read_units': 1}
```
```js JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const pc = new Pinecone();
const index = pc.index("INDEX_NAME", "INDEX_HOST").namespace("example-namespace");
const results = await index.listPaginated({ prefix: 'doc1#' });
console.log(results);
// Response:
// {
// vectors: [
// { id: 'doc1#19' }, { id: 'doc1#20' }, { id: 'doc1#21' }
// ],
// namespace: 'example-namespace',
// usage: { readUnits: 1 }
// }
```
```go Go theme={null}
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func prettifyStruct(obj interface{}) string {
bytes, _ := json.MarshalIndent(obj, "", " ")
return string(bytes)
}
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
idxConnection, err := pc.Index(pinecone.NewIndexConnParams{Host: "INDEX_HOST", Namespace: "example-namespace"})
if err != nil {
log.Fatalf("Failed to create IndexConnection for Host: %v", err)
}
limit := uint32(3)
paginationToken := "eyJza2lwX3Bhc3QiOiIwMDBkMTc4OC0zMDAxLTQwZmMtYjZjNC0wOWI2N2I5N2JjNDUiLCJwcmVmaXgiOm51bGx9"
res, err := idxConnection.ListVectors(ctx, &pinecone.ListVectorsRequest{
Limit: &limit,
paginationToken: &paginationToken,
})
if len(res.VectorIds) == 0 {
fmt.Println("No vectors found")
} else {
fmt.Printf(prettifyStruct(res))
}
}
// Response:
// {
// "vector_ids": [
// "doc1#chunk7",
// "doc1#chunk8",
// "doc1#chunk9"
// ],
// "usage": {
// "read_units": 1
// }
// }
```
```shell curl theme={null}
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
curl -X GET "https://$INDEX_HOST/vectors/list?namespace=example-namespace&paginationToken=mn23b4jB3Y9jpsS1" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10"
# Response:
# {
# "vectors": [
# { "id": "doc3#chunk1" },
# { "id": "doc5#chunk2" },
# { "id": "doc5#chunk3" },
# { "id": "doc5#chunk4" },
# ...
# ],
# "namespace": "example-namespace",
# "usage": {
# "readUnits": 1
# }
# }
```
# Manage serverless indexes
Source: https://docs.pinecone.io/guides/manage-data/manage-indexes
List, describe, configure, and delete serverless indexes in Pinecone, including tags, deletion protection, and metadata index configuration.
This page shows you how to manage your existing serverless indexes.
## List indexes
Use the [`list_indexes`](/reference/api/latest/control-plane/list_indexes) operation to get a complete description of all indexes in a project:
```Python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
index_list = pc.list_indexes()
print(index_list)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' })
const indexList = await pc.listIndexes();
console.log(indexList);
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.model.*;
public class ListIndexesExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
IndexList indexList = pc.listIndexes();
System.out.println(indexList);
}
}
```
```go Go theme={null}
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func prettifyStruct(obj interface{}) string {
bytes, _ := json.MarshalIndent(obj, "", " ")
return string(bytes)
}
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
idxs, err := pc.ListIndexes(ctx)
if err != nil {
log.Fatalf("Failed to list indexes: %v", err)
} else {
for _, index := range idxs {
fmt.Printf("index: %v\n", prettifyStruct(index))
}
}
}
```
```shell curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -i -X GET "https://api.pinecone.io/indexes" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10"
```
The response will look like this:
```python Python theme={null}
[{
"name": "docs-example-sparse",
"metric": "dotproduct",
"host": "docs-example-sparse-govk0nt.svc.aped-4627-b74a.pinecone.io",
"spec": {
"serverless": {
"cloud": "aws",
"region": "us-east-1"
}
},
"status": {
"ready": true,
"state": "Ready"
},
"vector_type": "sparse",
"dimension": null,
"deletion_protection": "disabled",
"tags": {
"environment": "development"
}
}, {
"name": "docs-example-dense",
"metric": "cosine",
"host": "docs-example-dense-govk0nt.svc.aped-4627-b74a.pinecone.io",
"spec": {
"serverless": {
"cloud": "aws",
"region": "us-east-1"
}
},
"status": {
"ready": true,
"state": "Ready"
},
"vector_type": "dense",
"dimension": 1536,
"deletion_protection": "disabled",
"tags": {
"environment": "development"
}
}]
```
```javascript JavaScript theme={null}
{
indexes: [
{
name: 'docs-example-sparse',
dimension: undefined,
metric: 'dotproduct',
host: 'docs-example-sparse-govk0nt.svc.aped-4627-b74a.pinecone.io',
deletionProtection: 'disabled',
tags: { environment: 'development', example: 'tag' },
embed: undefined,
spec: { pod: undefined, serverless: { cloud: 'aws', region: 'us-east-1' } },
status: { ready: true, state: 'Ready' },
vectorType: 'sparse'
},
{
name: 'docs-example-dense',
dimension: 1536,
metric: 'cosine',
host: 'docs-example-dense-govk0nt.svc.aped-4627-b74a.pinecone.io',
deletionProtection: 'disabled',
tags: { environment: 'development', example: 'tag' },
embed: undefined,
spec: { pod: undefined, serverless: { cloud: 'aws', region: 'us-east-1' } },
status: { ready: true, state: 'Ready' },
vectorType: 'dense'
}
]
}
```
```java Java theme={null}
class IndexList {
indexes: [class IndexModel {
name: docs-example-sparse
dimension: null
metric: dotproduct
host: docs-example-sparse-govk0nt.svc.aped-4627-b74a.pinecone.io
deletionProtection: disabled
tags: {environment=development}
embed: null
spec: class IndexModelSpec {
pod: null
serverless: class ServerlessSpec {
cloud: aws
region: us-east-1
additionalProperties: null
}
additionalProperties: null
}
status: class IndexModelStatus {
ready: true
state: Ready
additionalProperties: null
}
vectorType: sparse
additionalProperties: null
}, class IndexModel {
name: docs-example-dense
dimension: 1536
metric: cosine
host: docs-example-dense-govk0nt.svc.aped-4627-b74a.pinecone.io
deletionProtection: disabled
tags: {environment=development}
embed: null
spec: class IndexModelSpec {
pod: null
serverless: class ServerlessSpec {
cloud: aws
region: us-east-1
additionalProperties: null
}
additionalProperties: null
}
status: class IndexModelStatus {
ready: true
state: Ready
additionalProperties: null
}
vectorType: dense
additionalProperties: null
}]
additionalProperties: null
}
```
```go Go theme={null}
index: {
"name": "docs-example-sparse",
"host": "docs-example-sparse-govk0nt.svc.aped-4627-b74a.pinecone.io",
"metric": "dotproduct",
"vector_type": "sparse",
"deletion_protection": "disabled",
"dimension": null,
"spec": {
"serverless": {
"cloud": "aws",
"region": "us-east-1"
}
},
"status": {
"ready": true,
"state": "Ready"
},
"tags": {
"environment": "development"
}
}
index: {
"name": "docs-example-dense",
"host": "docs-example-dense-govk0nt.svc.aped-4627-b74a.pinecone.io",
"metric": "cosine",
"vector_type": "dense",
"deletion_protection": "disabled",
"dimension": 1536,
"spec": {
"serverless": {
"cloud": "aws",
"region": "us-east-1"
}
},
"status": {
"ready": true,
"state": "Ready"
},
"tags": {
"environment": "development"
}
}
```
```json curl theme={null}
{
"indexes": [
{
"name": "docs-example-sparse",
"vector_type": "sparse",
"metric": "dotproduct",
"dimension": null,
"status": {
"ready": true,
"state": "Ready"
},
"host": "docs-example-sparse-govk0nt.svc.aped-4627-b74a.pinecone.io",
"spec": {
"serverless": {
"region": "us-east-1",
"cloud": "aws"
}
},
"deletion_protection": "disabled",
"tags": {
"environment": "development"
}
},
{
"name": "docs-example-dense",
"vector_type": "dense",
"metric": "cosine",
"dimension": 1536,
"status": {
"ready": true,
"state": "Ready"
},
"host": "docs-example-dense-govk0nt.svc.aped-4627-b74a.pinecone.io",
"spec": {
"serverless": {
"region": "us-east-1",
"cloud": "aws"
}
},
"deletion_protection": "disabled",
"tags": {
"environment": "development"
}
}
]
}
```
With the Python SDK, you can use the `.names()` helper function to iterate over the index names in the `list_indexes()` response, for example:
```Python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
from pinecone import ServerlessSpec
for index_name in pc.list_indexes().names:
print(index_name)
```
## Describe an index
Use the [`describe_index`](/reference/api/latest/control-plane/describe_index/) endpoint to get a complete description of a specific index:
```Python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
pc.describe_index(name="docs-example")
```
```JavaScript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' });
await pc.describeIndex('docs-example');
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.model.*;
public class DescribeIndexExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("YOURE_API_KEY").build();
IndexModel indexModel = pc.describeIndex("docs-example");
System.out.println(indexModel);
}
}
```
```go Go theme={null}
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func prettifyStruct(obj interface{}) string {
bytes, _ := json.MarshalIndent(obj, "", " ")
return string(bytes)
}
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
idx, err := pc.DescribeIndex(ctx, "docs-example")
if err != nil {
log.Fatalf("Failed to describe index \"%v\": %v", idx.Name, err)
} else {
fmt.Printf("index: %v\n", prettifyStruct(idx))
}
}
```
```bash curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -i -X GET "https://api.pinecone.io/indexes/docs-example" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10"
```
The response will look like this:
```Python Python theme={null}
{'deletion_protection': 'disabled',
'dimension': 1536,
'host': 'docs-example-dense-govk0nt.svc.aped-4627-b74a.pinecone.io',
'metric': 'cosine',
'name': 'docs-example-dense',
'spec': {'serverless': {'cloud': 'aws', 'region': 'us-east-1'}},
'status': {'ready': True, 'state': 'Ready'},
'tags': {'environment': 'development'},
'vector_type': 'dense'}
```
```javaScript JavaScript theme={null}
{
name: 'docs-example-dense',
dimension: 1536,
metric: 'cosine',
host: 'docs-example-dense-govk0nt.svc.aped-4627-b74a.pinecone.io',
deletionProtection: 'disabled',
tags: { environment: 'development', example: 'tag' },
embed: undefined,
spec: { pod: undefined, serverless: { cloud: 'aws', region: 'us-east-1' } },
status: { ready: true, state: 'Ready' },
vectorType: 'dense'
}
```
```java Java theme={null}
class IndexModel {
name: docs-example-dense
dimension: 1536
metric: cosine
host: docs-example-dense-govk0nt.svc.aped-4627-b74a.pinecone.io
deletionProtection: disabled
tags: {environment=development}
embed: null
spec: class IndexModelSpec {
pod: null
serverless: class ServerlessSpec {
cloud: aws
region: us-east-1
additionalProperties: null
}
additionalProperties: null
}
status: class IndexModelStatus {
ready: true
state: Ready
additionalProperties: null
}
vectorType: dense
additionalProperties: null
}
```
```go Go theme={null}
index: {
"name": "docs-example-dense",
"host": "docs-example-dense-govk0nt.svc.aped-4627-b74a.pinecone.io",
"metric": "cosine",
"vector_type": "dense",
"deletion_protection": "disabled",
"dimension": 1536,
"spec": {
"serverless": {
"cloud": "aws",
"region": "us-east-1"
}
},
"status": {
"ready": true,
"state": "Ready"
},
"tags": {
"environment": "development"
}
}
```
```json curl theme={null}
{
"name": "docs-example-dense",
"vector_type": "dense",
"metric": "cosine",
"dimension": 1536,
"status": {
"ready": true,
"state": "Ready"
},
"host": "docs-example-dense-govk0nt.svc.aped-4627-b74a.pinecone.io",
"spec": {
"serverless": {
"region": "us-east-1",
"cloud": "aws"
}
},
"deletion_protection": "disabled",
"tags": {
"environment": "development"
}
}
```
**Do not target an index by name in production.**
When you target an index by name for data operations such as `upsert` and `query`, the SDK gets the unique DNS host for the index using the `describe_index` operation. This is convenient for testing but should be avoided in production because `describe_index` uses a different API than data operations and therefore adds an additional network call and point of failure. Instead, you should get an index host once and cache it for reuse or specify the host directly.
## Delete an index
Use the [`delete_index`](reference/api/latest/control-plane/delete_index) operation to delete an index and all of its associated resources.
```python Python theme={null}
# pip install "pinecone[grpc]"
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
pc.delete_index(name="docs-example")
```
```javascript JavaScript theme={null}
// npm install @pinecone-database/pinecone
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({
apiKey: 'YOUR_API_KEY'
});
await pc.deleteIndex('docs-example');
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
public class DeleteIndexExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
pc.deleteIndex("docs-example");
}
}
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
indexName := "docs-example"
err = pc.DeleteIndex(ctx, indexName)
if err != nil {
log.Fatalf("Failed to delete index: %v", err)
} else {
fmt.Println("Index \"%v\" deleted successfully", indexName)
}
}
```
```shell curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -i -X DELETE "https://api.pinecone.io/indexes/docs-example" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10"
```
If deletion protection is enabled on an index, requests to delete it will fail and return a `403 - FORBIDDEN` status with the following error:
```
Deletion protection is enabled for this index. Disable deletion protection before retrying.
```
Before you can delete such an index, you must first [disable deletion protection](/guides/manage-data/manage-indexes#configure-deletion-protection).
You can delete an index using the [Pinecone console](https://app.pinecone.io/organizations/-/projects/-/indexes). For the index you want to delete, click the three dots to the right of the index name, then click **Delete**.
## Associate an embedding model
[Integrated inference](/guides/index-data/indexing-overview#integrated-embedding) lets you upsert and search without extra steps for embedding data and reranking results.
To configure an existing serverless index for an embedding model, use the [`configure_index`](/reference/api/latest/control-plane/configure_index) operation as follows:
* Set `embed.model` to one of [Pinecone's hosted embedding models](/guides/index-data/create-an-index#embedding-models).
* Set `embed.field_map` to the name of the field in your source document that contains the data for embedding.
The `vector_type`, `metric`, and `dimension` of the index must be supported by the specified embedding model.
```python Python theme={null}
# pip install --upgrade pinecone
from pinecone import Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
pc.configure_index(
name="docs-example",
embed={
"model":"llama-text-embed-v2",
"field_map":{"text": "chunk_text"}
}
)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' });
await pc.configureIndex('docs-example', {
embed: {
model: 'llama-text-embed-v2',
fieldMap: { text: 'chunk_text' },
},
});
```
```json curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -s -X PATCH "https://api.pinecone.io/indexes/docs-example" \
-H "Content-Type: application/json" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"embed": {
"model": "llama-text-embed-v2",
"field_map": {
"text": "chunk_text"
}
}
}'
```
## Configure deletion protection
This feature requires [Pinecone API version](/reference/api/versioning) `2024-07`, [Python SDK](/reference/sdks/python/overview) v5.0.0, [Node.js SDK](/reference/sdks/node/overview) v3.0.0, [Java SDK](/reference/sdks/java/overview) v2.0.0, or [Go SDK](/reference/sdks/go/overview) v1.0.0 or later.
### Enable deletion protection
You can prevent an index and its data from accidental deleting when [creating a new index](/guides/index-data/create-an-index) or after its been created. In both cases, you set the `deletion_protection` parameter to `enabled`.
Enabling deletion protection does *not* prevent [namespace deletions](/guides/manage-data/manage-namespaces#delete-a-namespace).
To enable deletion protection when creating a new index:
```python Python theme={null}
# pip install "pinecone[grpc]"
# Serverless index
from pinecone.grpc import PineconeGRPC as Pinecone
from pinecone import ServerlessSpec
pc = Pinecone(api_key="YOUR_API_KEY")
pc.create_index(
name="docs-example",
dimension=1536,
metric="cosine",
spec=ServerlessSpec(
cloud="aws",
region="us-east-1"
),
deletion_protection="enabled"
)
```
```javascript JavaScript theme={null}
// npm install @pinecone-database/pinecone
// Serverles index
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({
apiKey: 'YOUR_API_KEY'
});
await pc.createIndex({
name: 'docs-example',
dimension: 1536,
metric: 'cosine',
spec: {
serverless: {
cloud: 'aws',
region: 'us-east-1'
}
},
deletionProtection: 'enabled',
});
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.model.IndexModel;
import org.openapitools.db_control.client.model.DeletionProtection;
// Serverless index
public class CreateServerlessIndexExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
pc.createServerlessIndex("docs-example", "cosine", 1536, "aws", "us-east-1", DeletionProtection.enabled);
}
}
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
// Serverless index
indexName := "docs-example"
vectorType := "dense"
dimension := int32(1536)
metric := pinecone.Cosine
deletionProtection := pinecone.DeletionProtectionDisabled
idx, err := pc.CreateServerlessIndex(ctx, &pinecone.CreateServerlessIndexRequest{
Name: indexName,
VectorType: &vectorType,
Dimension: &dimension,
Metric: &metric,
Cloud: pinecone.Aws,
Region: "us-east-1",
DeletionProtection: &deletionProtection,
Tags: &pinecone.IndexTags{ "environment": "development" },
})
if err != nil {
log.Fatalf("Failed to create serverless index: %v", err)
} else {
fmt.Printf("Successfully created serverless index: %v", idx.Name)
}
}
```
```shell curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
# Serverless index
curl -s "https://api.pinecone.io/indexes" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"name": "docs-example",
"dimension": 1536,
"metric": "cosine",
"spec": {
"serverless": {
"cloud": "aws",
"region": "us-east-1"
}
},
"deletion_protection": "enabled"
}'
```
To enable deletion protection when configuring an existing index:
```python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
pc.configure_index(
name="docs-example",
deletion_protection="enabled"
)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const client = new Pinecone({ apiKey: 'YOUR_API_KEY' });
await client.configureIndex('docs-example', { deletionProtection: 'enabled' });
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.model.*;
public class ConfigureIndexExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
pc.configureServerlessIndex("docs-example", DeletionProtection.ENABLED);
}
}
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
idx, err := pc.ConfigureIndex(ctx, "docs-example", pinecone.ConfigureIndexParams{DeletionProtection: "enabled"})
if err != nil {
log.Fatalf("Failed to configure index \"%v\": %v", idx.Name, err)
} else {
fmt.Printf("Successfully configured index \"%v\"", idx.Name)
}
}
```
```shell curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -s -X PATCH "https://api.pinecone.io/indexes/docs-example-curl" \
-H "Content-Type: application/json" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"deletion_protection": "enabled"
}'
```
When deletion protection is enabled on an index, requests to delete the index fail and return a `403 - FORBIDDEN` status with the following error:
```
Deletion protection is enabled for this index. Disable deletion protection before retrying.
```
### Disable deletion protection
Before you can [delete an index](#delete-an-index) with deletion protection enabled, you must first disable deletion protection as follows:
```python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
pc.configure_index(
name="docs-example",
deletion_protection="disabled"
)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const client = new Pinecone({ apiKey: 'YOUR_API_KEY' });
await client.configureIndex('docs-example', { deletionProtection: 'disabled' });
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.model.*;
public class ConfigureIndexExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
pc.configureServerlessIndex("docs-example", DeletionProtection.DISABLED);
}
}
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
idx, err := pc.ConfigureIndex(ctx, "docs-example", pinecone.ConfigureIndexParams{DeletionProtection: "disabled"})
if err != nil {
log.Fatalf("Failed to configure index \"%v\": %v", idx.Name, err)
} else {
fmt.Printf("Successfully configured index \"%v\"", idx.Name)
}
}
```
```shell curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -s -X PATCH "https://api.pinecone.io/indexes/docs-example-curl" \
-H "Content-Type: application/json" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"deletion_protection": "disabled"
}'
```
## Configure index tags
Tags are key-value pairs that you can use to categorize and identify the index.
### Add tags
To add tags to an index, use the `tags` parameter when [creating a new index](/guides/index-data/create-an-index) or configuring an existing index.
To add tags when creating a new index:
```python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
from pinecone import ServerlessSpec
pc = Pinecone(api_key="YOUR_API_KEY")
pc.create_index(
name="docs-example",
dimension=1536,
metric="cosine",
spec=ServerlessSpec(
cloud="aws",
region="us-east-1"
),
deletion_protection="disabled",
tags={
"example": "tag",
"environment": "development"
}
)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const client = new Pinecone({ apiKey: 'YOUR_API_KEY' });
await pc.createIndex({
name: 'docs-example',
dimension: 1536,
metric: 'cosine',
spec: {
serverless: {
cloud: 'aws',
region: 'us-east-1'
}
},
deletionProtection: 'disabled',
tags: { example: 'tag', environment: 'development' },
});
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.model.IndexModel;
import org.openapitools.db_control.client.model.DeletionProtection;
import java.util.HashMap;
// Serverless index
public class CreateServerlessIndexExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
HashMap tags = new HashMap<>();
tags.put("tag", "development");
pc.createServerlessIndex("docs-example", "cosine", 1536, "aws", "us-east-1", DeletionProtection.DISABLED, tags);
}
}
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
// Serverless index
idx, err := pc.CreateServerlessIndex(ctx, &pinecone.CreateServerlessIndexRequest{
Name: "docs-example",
Dimension: 1536,
Metric: pinecone.Cosine,
Cloud: pinecone.Aws,
Region: "us-east-1",
DeletionProtection: "disabled",
Tags: &pinecone.IndexTags{ "example": "tag", "environment": "development" },
})
if err != nil {
log.Fatalf("Failed to create serverless index: %v", err)
} else {
fmt.Printf("Successfully created serverless index: %v", idx.Name)
}
}
```
```shell curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
# Serverless index
curl -s "https://api.pinecone.io/indexes" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"name": "docs-example",
"dimension": 1536,
"metric": "cosine",
"spec": {
"serverless": {
"cloud": "aws",
"region": "us-east-1"
}
},
"tags": {
"example": "tag",
"environment": "development"
},
"deletion_protection": "disabled"
}'
```
You can add tags during index creation using the [Pinecone console](https://app.pinecone.io/organizations/-/projects/-/create-index/).
To add or update tags when configuring an existing index:
```python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
pc.configure_index(
name="docs-example",
tags={
example: "tag",
environment: "development"
}
)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const client = new Pinecone({ apiKey: 'YOUR_API_KEY' });
await client.configureIndex('docs-example', { tags: { example: 'tag', environment: 'development' }});
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.model.*;
import java.util.HashMap;
public class ConfigureIndexExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
HashMap tags = new HashMap<>();
tags.put("tag", "development");
pc.configureServerlessIndex("docs-example", DeletionProtection.ENABLED, tags);
}
}
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
idx, err := pc.ConfigureIndex(ctx,
"docs-example",
pinecone.ConfigureIndexParams{
Tags: pinecone.IndexTags{
"example": "tag",
"environment": "development",
},
},
)
if err != nil {
log.Fatalf("Failed to configure index \"%v\": %v", idx.Name, err)
} else {
fmt.Printf("Successfully configured index \"%v\"", idx.Name)
}
}
```
```shell curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -s -X PATCH "https://api.pinecone.io/indexes/docs-example-curl" \
-H "Content-Type: application/json" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"tags": {
"example": "tag",
"environment": "development"
}
}'
```
You can add or update tags when configuring an existing index using the [Pinecone console](https://app.pinecone.io/organizations/-/projects/-/indexes). Find the index to edit and click the **ellipsis (...) menu > Add tags**.
### View tags
To view the tags of an index, [list all indexes](/guides/manage-data/manage-indexes) in a project or [get information about a specific index](/guides/manage-data/manage-indexes).
### Remove tags
To remove a tag from an index, [configure the index](/reference/api/latest/control-plane/configure_index) and use the `tags` parameter to send the tag key with an empty value (`""`).
The following example removes the `example: tag` tag from `docs-example`:
```python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
pc.configure_index(
name="docs-example",
tags={"example": ""}
)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const client = new Pinecone({ apiKey: 'YOUR_API_KEY' });
await client.configureIndex('docs-example', { tags: { example: '' }});
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.model.*;
import java.util.HashMap;
public class ConfigureIndexExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
HashMap tags = new HashMap<>();
tags.put("example", "");
pc.configureServerlessIndex("docs-example", DeletionProtection.ENABLED, tags);
}
}
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
idx, err := pc.ConfigureIndex(ctx,
"docs-example",
pinecone.ConfigureIndexParams{
Tags: pinecone.IndexTags{
"example": "",
},
},
)
if err != nil {
log.Fatalf("Failed to configure index \"%v\": %v", idx.Name, err)
} else {
fmt.Printf("Successfully configured index \"%v\"", idx.Name)
}
}
```
```shell curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -s -X PATCH "https://api.pinecone.io/indexes/docs-example-curl" \
-H "Content-Type: application/json" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"tags": {
"example": ""
}
}'
```
You can remove tags from an index using the [Pinecone console](https://app.pinecone.io/organizations/-/projects/-/indexes). Find the index to edit and click the **ellipsis (...) menu > \_\_ tags**.
## List backups for an index
Serverless indexes can be [backed up](/guides/manage-data/back-up-an-index). You can [list all backups for a specific index](/reference/api/latest/control-plane/list_index_backups), as in the following example:
```python Python theme={null}
from pinecone import Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
index_backups = pc.list_backups(index_name="docs-example")
print(index_backups)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' })
const indexBackups = await pc.listBackups({ indexName: 'docs-example' });
console.log(indexBackups);
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.ApiException;
import org.openapitools.db_control.client.model.*;
public class CreateBackup {
public static void main(String[] args) throws ApiException {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
String indexName = "docs-example";
BackupList indexBackupList = pc.listIndexBackups(indexName);
System.out.println(indexBackupList);
}
}
```
```go Go theme={null}
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func prettifyStruct(obj interface{}) string {
bytes, _ := json.MarshalIndent(obj, "", " ")
return string(bytes)
}
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
indexName := "docs-example"
limit := 2
indexBackups, err := pc.ListBackups(ctx, &pinecone.ListBackupsParams{
Limit: &limit,
IndexName: &indexName,
})
if err != nil {
log.Fatalf("Failed to list backups: %v", err)
}
fmt.Printf(prettifyStruct(indexBackups))
}
```
```bash curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_NAME="docs-example"
curl -X GET "https://api.pinecone.io/indexes/$INDEX_NAME/backups" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-H "accept: application/json"
```
The example returns a response like the following:
```python Python theme={null}
[{
"backup_id": "8c85e612-ed1c-4f97-9f8c-8194e07bcf71",
"source_index_name": "docs-example",
"source_index_id": "f73b36c9-faf5-4a2c-b1d6-4013d8b1cc74",
"status": "Ready",
"cloud": "aws",
"region": "us-east-1",
"tags": {},
"name": "example-backup",
"description": "Monthly backup of production index",
"dimension": 1024,
"record_count": 98,
"namespace_count": 3,
"size_bytes": 1069169,
"created_at": "2025-05-15T00:52:10.809305882Z"
}]
```
```javascript JavaScript theme={null}
{
data: [
{
backupId: '8c85e612-ed1c-4f97-9f8c-8194e07bcf71',
sourceIndexName: 'docs-example',
sourceIndexId: 'f73b36c9-faf5-4a2c-b1d6-4013d8b1cc74',
name: 'example-backup',
description: 'Monthly backup of production index',
status: 'Ready',
cloud: 'aws',
region: 'us-east-1',
dimension: 1024,
metric: undefined,
recordCount: 98,
namespaceCount: 3,
sizeBytes: 1069169,
tags: {},
createdAt: '2025-05-14T16:37:25.625540Z'
}
],
pagination: undefined
}
```
```java Java theme={null}
class BackupList {
data: [class BackupModel {
backupId: 8c85e612-ed1c-4f97-9f8c-8194e07bcf71
sourceIndexName: docs-example
sourceIndexId: f73b36c9-faf5-4a2c-b1d6-4013d8b1cc74
name: example-backup
description: Monthly backup of production index
status: Initializing
cloud: aws
region: us-east-1
dimension: null
metric: null
recordCount: null
namespaceCount: null
sizeBytes: null
tags: {}
createdAt: 2025-05-16T19:46:26.248428Z
additionalProperties: null
}]
pagination: null
additionalProperties: null
}
```
```go Go theme={null}
{
"data": [
{
"backup_id": "bf2cda5d-b233-4a0a-aae9-b592780ad3ff",
"cloud": "aws",
"created_at": "2025-05-16T18:01:51.531129Z",
"description": "Monthly backup of production index",
"dimension": 0,
"name": "example-backup",
"namespace_count": 1,
"record_count": 96,
"region": "us-east-1",
"size_bytes": 86393,
"source_index_id": "bcb5b3c9-903e-4cb6-8b37-a6072aeb874f",
"source_index_name": "docs-example",
"status": "Ready",
"tags": {}
},
{
"backup_id": "e12269b0-a29b-4af0-9729-c7771dec03e3",
"cloud": "aws",
"created_at": "2025-05-14T17:00:45.803146Z",
"dimension": 0,
"name": "example-backup2",
"namespace_count": 1,
"record_count": 96,
"region": "us-east-1",
"size_bytes": 86393,
"source_index_id": "bcb5b3c9-903e-4cb6-8b37-a6072aeb874f",
"source_index_name": "docs-example",
"status": "Ready"
}
],
"pagination": {
"next": "eyJsaW1pdCI6Miwib2Zmc2V0IjoyfQ=="
}
}
```
```json curl theme={null}
{
"data":
[
{
"backup_id":"9947520e-d5a1-4418-a78d-9f464c9969da",
"source_index_id":"8433941a-dae7-43b5-ac2c-d3dab4a56b2b",
"source_index_name":"docs-example",
"tags":{},
"name":"example-backup",
"description":"Monthly backup of production index",
"status":"Pending",
"cloud":"aws",
"region":"us-east-1",
"dimension":1024,
"record_count":98,
"namespace_count":3,
"size_bytes":1069169,
"created_at":"2025-03-11T18:29:50.549505Z"
}
],
"pagination":null
}
```
You can view the backups for a specific index from either the [Backups](https://app.pinecone.io/organizations/-/projects/-/backups) tab or the [Indexes](https://app.pinecone.io/organizations/-/projects/-/indexes) tab in the Pinecone console.
# Manage namespaces
Source: https://docs.pinecone.io/guides/manage-data/manage-namespaces
Create, describe, list, and delete namespaces in Pinecone serverless indexes, including defining filterable metadata fields and schemas ahead of upsert.
## Create a namespace
This feature is available only on the `2025-10` version of the API.
Namespaces are created automatically as you [upsert](/guides/index-data/upsert-data) records. However, you can also create namespaces ahead of time using the [`create_namespace`](/reference/api/2025-10/data-plane/createnamespace) operation. Specify a name for the namespace and, optionally, the [metadata fields to index](/guides/index-data/create-an-index#metadata-indexing).
```python Python theme={null}
from pinecone import Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
index = pc.Index(host="INDEX_HOST")
namespace = index.create_namespace(
name="example-namespace",
schema={
"fields": {
"document_id": {"filterable": True},
"document_title": {"filterable": True},
"chunk_number": {"filterable": True},
"document_url": {"filterable": True},
"created_at": {"filterable": True}
}
}
)
print(namespace)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' })
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
const index = pc.index('INDEX_NAME', 'INDEX_HOST');
const namespace = await index.createNamespace({
name: 'example-namespace',
schema: {
fields: {
document_id: { filterable: true },
document_title: { filterable: true },
chunk_number: { filterable: true },
document_url: { filterable: true },
created_at: { filterable: true }
}
}
});
console.log(namespace);
```
```java Java theme={null}
import io.pinecone.clients.Index;
import io.pinecone.configs.PineconeConfig;
import io.pinecone.configs.PineconeConnection;
import io.pinecone.proto.NamespaceDescription;
import io.pinecone.proto.MetadataSchema;
import io.pinecone.proto.MetadataSchemaField;
public class CreateNamespaceExample {
public static void main(String[] args) {
PineconeConfig config = new PineconeConfig("YOUR_API_KEY");
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
config.setHost("INDEX_HOST");
PineconeConnection connection = new PineconeConnection(config);
Index index = new Index(config, connection, "INDEX_NAME");
MetadataSchemaField filterable = MetadataSchemaField.newBuilder()
.setFilterable(true)
.build();
MetadataSchema schema = MetadataSchema.newBuilder()
.putFields("document_id", filterable)
.putFields("document_title", filterable)
.putFields("chunk_number", filterable)
.putFields("document_url", filterable)
.putFields("created_at", filterable)
.build();
NamespaceDescription namespace = index.createNamespace("example-namespace", schema);
System.out.println(namespace);
}
}
```
```go Go theme={null}
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func prettifyStruct(obj interface{}) string {
bytes, _ := json.MarshalIndent(obj, "", " ")
return string(bytes)
}
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
idxConnection, err := pc.Index(pinecone.NewIndexConnParams{Host: "INDEX_HOST"})
if err != nil {
log.Fatalf("Failed to create IndexConnection for Host: %v", err)
}
namespace, err := idxConnection.CreateNamespace(ctx, &pinecone.CreateNamespaceParams{
Name: "example-namespace",
Schema: &pinecone.MetadataSchema{
Fields: map[string]pinecone.MetadataSchemaField{
"document_id": {Filterable: true},
"document_title": {Filterable: true},
"chunk_number": {Filterable: true},
"document_url": {Filterable: true},
"created_at": {Filterable: true},
},
},
})
if err != nil {
log.Fatalf("Failed to create namespace: %v", err)
}
fmt.Printf(prettifyStruct(namespace))
}
```
```shell curl theme={null}
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
curl "https://$INDEX_HOST/namespaces" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"name": "example-namespace",
"schema": {
"fields": {
"document_id": {"filterable": true},
"document_title": {"filterable": true},
"chunk_number": {"filterable": true},
"document_url": {"filterable": true},
"created_at": {"filterable": true}
}
}
}'
```
The response will look like the following:
```json theme={null}
{
"name": "example-namespace",
"record_count": "0",
"schema": {
"fields": {
"document_title": {
"filterable": true
},
"document_url": {
"filterable": true
},
"chunk_number": {
"filterable": true
},
"document_id": {
"filterable": true
},
"created_at": {
"filterable": true
}
}
}
}
```
## List all namespaces in an index
Use the [`list_namespaces`](/reference/api/latest/data-plane/listnamespaces) operation to list all namespaces in a serverless index.
Up to 100 namespaces are returned at a time by default, in sorted order (bitwise “C” collation). If the `limit` parameter is set, up to that number of namespaces are returned instead. Whenever there are additional namespaces to return, the response also includes a `pagination_token` that you can use to get the next batch of namespaces. When the response does not include a `pagination_token`, there are no more namespaces to return.
```python Python theme={null}
# Not supported with pinecone["grpc"] extras installed
from pinecone import Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
index = pc.Index(host="INDEX_HOST")
# Implicit pagination using a generator function
for namespace in index.list_namespaces():
print(namespace.name, ":", namespace.record_count)
# Manual pagination
namespaces = index.list_namespaces_paginated(
limit=2,
pagination_token="eyJza2lwX3Bhc3QiOiIxMDEwMy0="
)
print(namespaces)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' })
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
var index = pinecone.Index(host: "INDEX_HOST");
const namespaceList = await index.listNamespaces();
console.log(namespaceList);
```
```java Java theme={null}
import io.pinecone.clients.AsyncIndex;
import io.pinecone.clients.Index;
import io.pinecone.configs.PineconeConfig;
import io.pinecone.configs.PineconeConnection;
import io.pinecone.proto.ListNamespacesResponse;
import org.openapitools.db_data.client.ApiException;
public class Namespaces {
public static void main(String[] args) throws ApiException {
PineconeConfig config = new PineconeConfig("YOUR_API_KEY");
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
config.setHost("INDEX_HOST");
PineconeConnection connection = new PineconeConnection(config);
Index index = new Index(config, connection, "docs-example");
// List all namespaces with default pagination limit (100)
ListNamespacesResponse listNamespacesResponse = index.listNamespaces(null, null);
// List all namespaces with pagination limit of 2
ListNamespacesResponse listNamespacesResponseWithLimit = index.listNamespaces(2);
// List all namespaces with pagination limit and token
ListNamespacesResponse listNamespacesResponsePaginated = index.listNamespaces(5, "eyJza2lwX3Bhc3QiOiIxMDEwMy0=");
System.out.println(listNamespacesResponseWithLimit);
}
}
```
```go Go theme={null}
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func prettifyStruct(obj interface{}) string {
bytes, _ := json.MarshalIndent(obj, "", " ")
return string(bytes)
}
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
idxConnection, err := pc.Index(pinecone.NewIndexConnParams{Host: "INDEX_HOST"})
if err != nil {
log.Fatalf("Failed to create IndexConnection for Host: %v", err)
}
limit := uint32(10)
namespaces, err := idxConnection.ListNamespaces(ctx, &pinecone.ListNamespacesParams{
Limit: &limit,
})
if err != nil {
log.Fatalf("Failed to list namespaces: %v", err)
}
fmt.Printf(prettifyStruct(namespaces))
}
```
```shell curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
curl -X GET "https://$INDEX_HOST/namespaces" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10"
```
The response will look like the following:
```plaintext Python theme={null}
# Implicit pagination (print output from: for n in index.list_namespaces(): print(n.name, ":", n.record_count))
example-namespace : 20000
example-namespace2 : 10500
example-namespace3 : 10000
...
# Manual pagination (response from list_namespaces_paginated())
{
"namespaces": [
{"name": "example-namespace", "record_count": "20000"},
{"name": "example-namespace2", "record_count": "10500"}
],
"pagination": {"next": "Tm90aGluZyB0byBzZWUgaGVyZQo="}
}
```
```javascript JavaScript theme={null}
{
namespaces: [
{ name: 'example-namespace', recordCount: '20000' },
{ name: 'example-namespace2', recordCount: '10500' },
...
],
pagination: "Tm90aGluZyB0byBzZWUgaGVyZQo="
}
```
```java Java theme={null}
namespaces {
name: "example-namespace"
record_count: 20000
}
namespaces {
name: "example-namespace2"
record_count: 10500
}
pagination {
next: "eyJza2lwX3Bhc3QiOiJlZDVhYzFiNi1kMDFiLTQ2NTgtYWVhZS1hYjJkMGI2YzBiZjQiLCJwcmVmaXgiOm51bGx9"
}
```
```go Go theme={null}
{
"Namespaces": [
{
"name": "example-namespace",
"record_count": 20000
},
{
"name": "example-namespace2",
"record_count": 10500
},
...
],
"Pagination": {
"next": "eyJza2lwX3Bhc3QiOiIyNzQ5YTU1YS0zZTQ2LTQ4MDItOGFlNi1hZTJjZGNkMTE5N2IiLCJwcmVmaXgiOm51bGx9"
}
}
```
```json curl theme={null}
{
"namespaces": [
{
"name": "example-namespace",
"record_count": 20000
},
{
"name": "example-namespace2",
"record_count": 10500
},
...
],
"pagination": {
"next": "Tm90aGluZyB0byBzZWUgaGVyZQo="
}
}
```
## Describe a namespace
Use the [`describe_namespace`](/reference/api/latest/data-plane/describenamespace) operation to get details about a namespace in a serverless index, including the total number of vectors in the namespace.
```python Python theme={null}
# Not supported with pinecone["grpc"] extras installed
from pinecone import Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
index = pc.Index(host="INDEX_HOST")
namespace = index.describe_namespace(namespace="example-namespace")
print(namespace)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' })
const index = pc.index('docs-example');
const namespace = await index.describeNamespace('example-namespace');
console.log(namespace);
```
```java Java theme={null}
import io.pinecone.clients.Index;
import io.pinecone.configs.PineconeConfig;
import io.pinecone.configs.PineconeConnection;
import io.pinecone.proto.NamespaceDescription;
import org.openapitools.db_data.client.ApiException;
public class Namespaces {
public static void main(String[] args) throws ApiException {
PineconeConfig config = new PineconeConfig("YOUR_API_KEY");
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
config.setHost("INDEX_HOST");
PineconeConnection connection = new PineconeConnection(config);
Index index = new Index(config, connection, "docs-example");
NamespaceDescription namespaceDescription = index.describeNamespace("example-namespace");
System.out.println(namespaceDescription);
}
}
```
```go Go theme={null}
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func prettifyStruct(obj interface{}) string {
bytes, _ := json.MarshalIndent(obj, "", " ")
return string(bytes)
}
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
idxConnection, err := pc.Index(pinecone.NewIndexConnParams{Host: "INDEX_HOST"})
if err != nil {
log.Fatalf("Failed to create IndexConnection for Host: %v", err)
}
namespace, err := idxConnection.DescribeNamespace(ctx, "example-namespace")
if err != nil {
log.Fatalf("Failed to describe namespace: %v", err)
}
fmt.Printf(prettifyStruct(namespace))
}
```
```shell curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
NAMESPACE="NAMESPACE_NAME" # To target the default namespace, use "__default__".
curl -X GET "https://$INDEX_HOST/namespaces/$NAMESPACE" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10"
```
The response will look like the following:
```python Python theme={null}
{
"name": "example-namespace",
"record_count": "20000"
}
```
```javascript JavaScript theme={null}
{ name: 'example-namespace', recordCount: '20000' }
```
```java Java theme={null}
name: "example-namespace"
record_count: 20000
```
```go Go theme={null}
{
"name": "example-namespace",
"record_count": 20000
}
```
```json curl theme={null}
{
"name": "example-namespace",
"record_count": 20000
}
```
## Delete a namespace
Use the [`delete_namespace`](/reference/api/latest/data-plane/deletenamespace) operation to delete a namespace in a serverless index.
Deleting a namespace is irreversible. All data in the namespace is permanently deleted.
```python Python theme={null}
# Not supported with pinecone["grpc"] extras installed
from pinecone import Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
index = pc.Index(host="INDEX_HOST")
index.delete_namespace(namespace="example-namespace")
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' })
const index = pc.index('INDEX_NAME', 'INDEX_HOST');
const namespace = await index.deleteNamespace('example-namespace');
console.log(namespace);
```
```java Java theme={null}
import io.pinecone.clients.Index;
import io.pinecone.configs.PineconeConfig;
import io.pinecone.configs.PineconeConnection;
import java.util.concurrent.ExecutionException;
public class DeleteNamespace {
public static void main(String[] args) throws ExecutionException, InterruptedException {
PineconeConfig config = new PineconeConfig("YOUR_API_KEY");
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
config.setHost("INDEX_HOST");
PineconeConnection connection = new PineconeConnection(config);
Index index = new Index(config, connection, "docs-example");
index.deleteNamespace("example-namespace");
}
}
```
```go Go theme={null}
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func prettifyStruct(obj interface{}) string {
bytes, _ := json.MarshalIndent(obj, "", " ")
return string(bytes)
}
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
idxConnection, err := pc.Index(pinecone.NewIndexConnParams{Host: "INDEX_HOST"})
if err != nil {
log.Fatalf("Failed to create IndexConnection for Host: %v", err)
}
err := idxConnection.DeleteNamespace(ctx, "example-namespace")
if err != nil {
log.Fatalf("Failed to delete namespace: %v", err)
}
}
```
```shell curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
NAMESPACE="NAMESPACE_NAME" # To target the default namespace, use "__default__".
curl -X DELETE "https://$INDEX_HOST/namespaces/$NAMESPACE" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10"
```
## Rename a namespace
Pinecone does not support renaming namespaces directly. Instead, you must [delete the records](/guides/manage-data/delete-data) in the namespace and [upsert the records](/guides/index-data/upsert-data) to a new namespace.
## Move records to a new namespace
Pinecone does not support moving records between namespaces directly. Instead, you must [delete the records](/guides/manage-data/delete-data) in the old namespace and [upsert the records](/guides/index-data/upsert-data) to the new namespace.
# Restore an index
Source: https://docs.pinecone.io/guides/manage-data/restore-an-index
Restore a Pinecone serverless index from a backup, change the index name, tags, or deletion protection, and preserve embedding model configuration.
## Create a serverless index from a backup
When restoring a serverless index from backup, you can change the index name, tags, and deletion protection setting. All other properties of the restored index will remain identical to the source index, including cloud and region by default, dimension and similarity metric, and associated embedding model when restoring an index with [integrated embedding](/guides/index-data/indexing-overview#integrated-embedding). To restore a backup into a different region than the source index, see [Restore to a different region](#restore-to-a-different-region).
To [create a serverless index from a backup](/reference/api/latest/control-plane/create_index_from_backup), provide the ID of the backup, the name of the new index, and, optionally, changes to the index tags and deletion protection settings:
```python Python theme={null}
from pinecone import Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
pc.create_index_from_backup(
backup_id="a65ff585-d987-4da5-a622-72e19a6ed5f4",
name="restored-index",
tags={
"tag0": "val0",
"tag1": "val1"
},
deletion_protection="enabled"
)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' })
const response = await pc.createIndexFromBackup({
backupId: 'a65ff585-d987-4da5-a622-72e19a6ed5f4',
name: 'restored-index',
tags: {
tag0: 'val0',
tag1: 'val1'
},
deletionProtection: 'enabled'
});
console.log(response);
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.ApiException;
import org.openapitools.db_control.client.model.*;
public class CreateIndexFromBackup {
public static void main(String[] args) throws ApiException {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
String backupID = "a65ff585-d987-4da5-a622-72e19a6ed5f4";
String indexName = "restored-index";
CreateIndexFromBackupResponse backupResponse = pc.createIndexFromBackup(backupID, indexName);
System.out.println(backupResponse);
}
}
```
```go Go theme={null}
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"time"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func prettifyStruct(obj interface{}) string {
bytes, _ := json.MarshalIndent(obj, "", " ")
return string(bytes)
}
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
indexName := "restored-index"
restoredIndexTags := pinecone.IndexTags{"restored_on": time.Now().Format("2006-01-02 15:04")}
createIndexFromBackupResp, err := pc.CreateIndexFromBackup(ctx, &pinecone.CreateIndexFromBackupParams{
BackupId: "e12269b0-a29b-4af0-9729-c7771dec03e3",
Name: indexName,
Tags: &restoredIndexTags,
})
fmt.Printf(prettifyStruct(createIndexFromBackupResp))
}
```
```bash curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
BACKUP_ID="a65ff585-d987-4da5-a622-72e19a6ed5f4"
curl "https://api.pinecone.io/backups/$BACKUP_ID/create-index" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-H 'Content-Type: application/json' \
-d '{
"name": "restored-index",
"tags": {
"tag0": "val0",
"tag1": "val1"
},
"deletion_protection": "enabled"
}'
```
The example returns a response like the following:
```python Python theme={null}
{'deletion_protection': 'enabled',
'dimension': 1024,
'embed': {'dimension': 1024,
'field_map': {'text': 'chunk_text'},
'metric': 'cosine',
'model': 'multilingual-e5-large',
'read_parameters': {'input_type': 'query', 'truncate': 'END'},
'vector_type': 'dense',
'write_parameters': {'input_type': 'passage', 'truncate': 'END'}},
'host': 'example-dense-index-python3-govk0nt.svc.aped-4627-b74a.pinecone.io',
'metric': 'cosine',
'name': 'example-dense-index-python3',
'spec': {'serverless': {'cloud': 'aws', 'region': 'us-east-1'}},
'status': {'ready': True, 'state': 'Ready'},
'tags': {'tag0': 'val0', 'tag1': 'val1'},
'vector_type': 'dense'}
```
```javascript JavaScript theme={null}
{
restoreJobId: 'e9ba8ff8-7948-4cfa-ba43-34227f6d30d4',
indexId: '025117b3-e683-423c-b2d1-6d30fbe5027f'
}
```
```java Java theme={null}
class CreateIndexFromBackupResponse {
restoreJobId: e9ba8ff8-7948-4cfa-ba43-34227f6d30d4
indexId: 025117b3-e683-423c-b2d1-6d30fbe5027f
additionalProperties: null
}
```
```go Go theme={null}
{
"index_id": "025117b3-e683-423c-b2d1-6d30fbe5027f",
"restore_job_id": "e9ba8ff8-7948-4cfa-ba43-34227f6d30d4"
}
```
```json curl theme={null}
{
"restore_job_id":"e9ba8ff8-7948-4cfa-ba43-34227f6d30d4",
"index_id":"025117b3-e683-423c-b2d1-6d30fbe5027f"
}
```
You can create a serverless index from a backup using the [Pinecone console](https://app.pinecone.io/organizations/-/projects).
## Restore to a different region
The [create index from backup](/reference/api/latest/control-plane/create_index_from_backup) endpoint always creates the new index in the same cloud and region as the backup. To restore a backup into a different region, use the `unstable` version of the [create index](/reference/api/latest/control-plane/create_index) endpoint instead. Specify the backup as `source_backup_id` within `spec.serverless` and set the target `region` there.
The following rules apply:
* The target region must be on the same cloud provider as the backup. Restoring to a different cloud provider is not supported.
* The backup must be in the current Pinecone project, and the new index is created in the same project.
* The `dimension`, `metric`, and `vector_type` must match the source index.
* Restoring to a different region is not supported for BYOC indexes.
Restoring to a different region is in [public preview](/release-notes/feature-availability). It is available through the `unstable` API version and the REST API only.
For example, the following request restores a backup of a dense index hosted in the AWS `us-east-1` region into a new index in the AWS `us-west-2` region:
```bash curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl "https://api.pinecone.io/indexes" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "Content-Type: application/json" \
-H "X-Pinecone-Api-Version: unstable" \
-d '{
"name": "restored-index",
"vector_type": "dense",
"dimension": 1536,
"metric": "cosine",
"spec": {
"serverless": {
"cloud": "aws",
"region": "us-west-2",
"source_backup_id": "a65ff585-d987-4da5-a622-72e19a6ed5f4"
}
}
}'
```
Because the backup data is copied between regions, restoring to a different region can take longer than restoring within the same region. If restoring to a different region is not yet available for the backup's region, the request fails with a `412 Precondition Failed` error.
## List restore jobs
You can [list all restore jobs](/reference/api/latest/control-plane/list_restore_jobs) as follows.
Up to 100 restore jobs are returned at a time by default, in sorted order (bitwise “C” collation). If the `limit` parameter is set, up to that number of restore jobs are returned instead. Whenever there are additional restore jobs to return, the response also includes a `pagination_token` that you can use to get the next batch of jobs. When the response does not include a `pagination_token`, there are no more restore jobs to return.
```python Python theme={null}
from pinecone import Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
restore_jobs = pc.list_restore_jobs()
print(restore_jobs)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' })
const restoreJobs = await pc.listRestoreJobs();
console.log(restoreJobs);
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.ApiException;
import org.openapitools.db_control.client.model.*;
public class CreateIndexFromBackup {
public static void main(String[] args) throws ApiException {
Pinecone pc = new Pinecone.Builder("YOUR_API-KEY").build();
// List all restore jobs with default pagination limit
RestoreJobList restoreJobList = pc.listRestoreJobs(null, null);
// List all restore jobs with pagination limit of 5
RestoreJobList restoreJobListWithLimit = pc.listRestoreJobs(5);
// List all restore jobs with pagination limit and token
RestoreJobList restoreJobListPaginated = pc.listRestoreJobs(5, "eyJza2lwX3Bhc3QiOiIxMDEwMy0=");
System.out.println(restoreJobList);
System.out.println(restoreJobListWithLimit);
System.out.println(restoreJobListPaginated);
}
}
```
```go Go theme={null}
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func prettifyStruct(obj interface{}) string {
bytes, _ := json.MarshalIndent(obj, "", " ")
return string(bytes)
}
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
limit := 2
restoreJobs, err := pc.ListRestoreJobs(ctx, &pinecone.ListRestoreJobsParams{
Limit: &limit,
})
if err != nil {
log.Fatalf("Failed to list restore jobs: %v", err)
}
fmt.Printf(prettifyStruct(restoreJobs))
}
```
```bash curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl "https://api.pinecone.io/restore-jobs" \
-H "X-Pinecone-Api-Version: 2025-10" \
-H "Api-Key: $PINECONE_API_KEY"
```
The example returns a response like the following:
```python Python theme={null}
[{
"restore_job_id": "06b08366-a0a9-404d-96c2-e791c71743e5",
"backup_id": "95707edb-e482-49cf-b5a5-312219a51a97",
"target_index_name": "restored-index",
"target_index_id": "027aff93-de40-4f48-a573-6dbcd654f961",
"status": "Completed",
"created_at": "2025-05-15T13:59:51.439479+00:00",
"completed_at": "2025-05-15T14:00:09.222998+00:00",
"percent_complete": 100.0
}, {
"restore_job_id": "4902f735-b876-4e53-a05c-bc01d99251cb",
"backup_id": "8c85e612-ed1c-4f97-9f8c-8194e07bcf71",
"target_index_name": "restored-index2",
"target_index_id": "027aff93-de40-4f48-a573-6dbcd654f961",
"status": "Completed",
"created_at": "2025-05-15T21:06:19.906074+00:00",
"completed_at": "2025-05-15T21:06:39.360509+00:00",
"percent_complete": 100.0
}]
```
```javascript JavaScript theme={null}
{
data: [
{
restoreJobId: '69acc1d0-9105-4fcb-b1db-ebf97b285c5e',
backupId: '8c85e612-ed1c-4f97-9f8c-8194e07bcf71',
targetIndexName: 'restored-index2',
targetIndexId: 'e6c0387f-33db-4227-9e91-32181106e56b',
status: 'Completed',
createdAt: 2025-05-14T17:25:59.378Z,
completedAt: 2025-05-14T17:26:23.997Z,
percentComplete: 100
},
{
restoreJobId: '9857add2-99d4-4399-870e-aa7f15d8d326',
backupId: '94a63aeb-efae-4f7a-b059-75d32c27ca57',
targetIndexName: 'restored-index',
targetIndexId: '0d8aed24-adf8-4b77-8e10-fd674309dc85',
status: 'Completed',
createdAt: 2025-04-25T18:14:05.227Z,
completedAt: 2025-04-25T18:14:11.074Z,
percentComplete: 100
}
],
pagination: undefined
}
```
```java Java theme={null}
class RestoreJobList {
data: [class RestoreJobModel {
restoreJobId: cf597d76-4484-4b6c-b07c-2bfcac3388aa
backupId: 0d75b99f-be61-4a93-905e-77201286c02e
targetIndexName: restored-index
targetIndexId: 8a810881-1505-46c0-b906-947c048b15f5
status: Completed
createdAt: 2025-05-16T20:09:18.700631Z
completedAt: 2025-05-16T20:11:30.673296Z
percentComplete: 100.0
additionalProperties: null
}, class RestoreJobModel {
restoreJobId: 4902f735-b876-4e53-a05c-bc01d99251cb
backupId: 8c85e612-ed1c-4f97-9f8c-8194e07bcf71
targetIndexName: restored-index2
targetIndexId: 710cb6e6-bfb4-4bf5-a425-9754e5bbc832
status: Completed
createdAt: 2025-05-15T21:06:19.906074Z
completedAt: 2025-05-15T21:06:39.360509Z
percentComplete: 100.0
additionalProperties: null
}]
pagination: class PaginationResponse {
next: eyJsaW1pdCI6Miwib2Zmc2V0IjoyfQ==
additionalProperties: null
}
additionalProperties: null
}
```
```go Go theme={null}
{
"data": [
{
"backup_id": "8c85e612-ed1c-4f97-9f8c-8194e07bcf71",
"completed_at": "2025-05-16T20:11:30.673296Z",
"created_at": "2025-05-16T20:09:18.700631Z",
"percent_complete": 100,
"restore_job_id": "e9ba8ff8-7948-4cfa-ba43-34227f6d30d4",
"status": "Completed",
"target_index_id": "025117b3-e683-423c-b2d1-6d30fbe5027f",
"target_index_name": "restored-index"
},
{
"backup_id": "95707edb-e482-49cf-b5a5-312219a51a97",
"completed_at": "2025-05-15T21:04:34.2463Z",
"created_at": "2025-05-15T21:04:15.949067Z",
"percent_complete": 100,
"restore_job_id": "eee4f8b8-cd3e-45fe-9ed5-93c28e237f24",
"status": "Completed",
"target_index_id": "5a0d555f-7ccd-422a-a3a6-78f7b73350c0",
"target_index_name": "restored-index2"
}
],
"pagination": {
"next": "eyJsaW1pdCI6MTAsIm9mZnNldCI6MTB9"
}
}
```
```json curl theme={null}
{
"data": [
{
"restore_job_id": "9857add2-99d4-4399-870e-aa7f15d8d326",
"backup_id": "94a63aeb-efae-4f7a-b059-75d32c27ca57",
"target_index_name": "restored-index",
"target_index_id": "0d8aed24-adf8-4b77-8e10-fd674309dc85",
"status": "Completed",
"created_at": "2025-04-25T18:14:05.227526Z",
"completed_at": "2025-04-25T18:14:11.074618Z",
"percent_complete": 100
},
{
"restore_job_id": "69acc1d0-9105-4fcb-b1db-ebf97b285c5e",
"backup_id": "8c85e612-ed1c-4f97-9f8c-8194e07bcf71",
"target_index_name": "restored-index2",
"target_index_id": "e6c0387f-33db-4227-9e91-32181106e56b",
"status": "Completed",
"created_at": "2025-05-14T17:25:59.378989Z",
"completed_at": "2025-05-14T17:26:23.997284Z",
"percent_complete": 100
}
],
"pagination": null
}
```
## View restore job details
You can [view the details of a specific restore job](/reference/api/latest/control-plane/describe_restore_job), as in the following example:
```python Python theme={null}
from pinecone import Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
restore_job = pc.describe_restore_job(job_id="9857add2-99d4-4399-870e-aa7f15d8d326")
print(restore_job)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' })
const restoreJob = await pc.describeRestoreJob('9857add2-99d4-4399-870e-aa7f15d8d326');
console.log(restoreJob);
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.ApiException;
import org.openapitools.db_control.client.model.*;
public class CreateIndexFromBackup {
public static void main(String[] args) throws ApiException {
Pinecone pc = new Pinecone.Builder("YOUR_API-KEY").build();
RestoreJobModel restoreJob = pc.describeRestoreJob("9857add2-99d4-4399-870e-aa7f15d8d326");
System.out.println(restoreJob);
}
}
```
```go Go theme={null}
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func prettifyStruct(obj interface{}) string {
bytes, _ := json.MarshalIndent(obj, "", " ")
return string(bytes)
}
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
restoreJob, err := pc.DescribeRestoreJob(ctx, "e9ba8ff8-7948-4cfa-ba43-34227f6d30d4")
if err != nil {
log.Fatalf("Failed to describe restore job: %v", err)
}
fmt.Printf(prettifyStruct(restoreJob))
}
```
```bash curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
JOB_ID="9857add2-99d4-4399-870e-aa7f15d8d326"
curl "https://api.pinecone.io/restore-jobs/$JOB_ID" \
-H "X-Pinecone-Api-Version: 2025-10" \
-H "Api-Key: $PINECONE_API_KEY" \
-H 'accept: application/json'
```
The example returns a response like the following:
```python Python theme={null}
{'backup_id': '94a63aeb-efae-4f7a-b059-75d32c27ca57',
'completed_at': datetime.datetime(2025, 4, 25, 18, 14, 11, 74618, tzinfo=tzutc()),
'created_at': datetime.datetime(2025, 4, 25, 18, 14, 5, 227526, tzinfo=tzutc()),
'percent_complete': 100.0,
'restore_job_id': '9857add2-99d4-4399-870e-aa7f15d8d326',
'status': 'Completed',
'target_index_id': '0d8aed24-adf8-4b77-8e10-fd674309dc85',
'target_index_name': 'restored-index'}
```
```javascript JavaScript theme={null}
{
restoreJobId: '9857add2-99d4-4399-870e-aa7f15d8d326',
backupId: '94a63aeb-efae-4f7a-b059-75d32c27ca57',
targetIndexName: 'restored-index',
targetIndexId: '0d8aed24-adf8-4b77-8e10-fd674309dc85',
status: 'Completed',
createdAt: 2025-04-25T18:14:05.227Z,
completedAt: 2025-04-25T18:14:11.074Z,
percentComplete: 100
}
```
```java Java theme={null}
class RestoreJobModel {
restoreJobId: cf597d76-4484-4b6c-b07c-2bfcac3388aa
backupId: 0d75b99f-be61-4a93-905e-77201286c02e
targetIndexName: restored-index
targetIndexId: 0d8aed24-adf8-4b77-8e10-fd674309dc85
status: Completed
createdAt: 2025-05-16T20:09:18.700631Z
completedAt: 2025-05-16T20:11:30.673296Z
percentComplete: 100.0
additionalProperties: null
}
```
```go Go theme={null}
{
"backup_id": "8c85e612-ed1c-4f97-9f8c-8194e07bcf71",
"completed_at": "2025-05-16T20:11:30.673296Z",
"created_at": "2025-05-16T20:09:18.700631Z",
"percent_complete": 100,
"restore_job_id": "e9ba8ff8-7948-4cfa-ba43-34227f6d30d4",
"status": "Completed",
"target_index_id": "025117b3-e683-423c-b2d1-6d30fbe5027f",
"target_index_name": "restored-index"
}
```
```json curl theme={null}
{
"restore_job_id": "9857add2-99d4-4399-870e-aa7f15d8d326",
"backup_id": "94a63aeb-efae-4f7a-b059-75d32c27ca57",
"target_index_name": "restored-index",
"target_index_id": "0d8aed24-adf8-4b77-8e10-fd674309dc85",
"status": "Completed",
"created_at": "2025-04-25T18:14:05.227526Z",
"completed_at": "2025-04-25T18:14:11.074618Z",
"percent_complete": 100
}
```
# Target an index
Source: https://docs.pinecone.io/guides/manage-data/target-an-index
Target a Pinecone index by host URL (recommended for production) or by name for data operations like upsert, query, and fetch across SDKs.
**Do not target an index by name in production.**
When you target an index by name for data operations such as `upsert` and `query`, the SDK gets the unique DNS host for the index using the `describe_index` operation. This is convenient for testing but should be avoided in production because `describe_index` uses a different API than data operations and therefore adds an additional network call and point of failure. Instead, you should get an index host once and cache it for reuse or specify the host directly.
## Target by index host (recommended)
This method is recommended for production:
When using Private Endpoints for private connectivity between your application and Pinecone, you must target the index using the [Private Endpoint URL](/guides/production/configure-private-endpoints#read-and-write-data) for the host.
```Python Python {5} theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
index = pc.Index(host="INDEX_HOST")
```
```javascript JavaScript {6} theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' });
// For the Node.js SDK, you must specify both the index host and name.
const index = pc.index("INDEX_NAME", "INDEX_HOST");
```
```java Java {11} theme={null}
import io.pinecone.clients.Index;
import io.pinecone.configs.PineconeConfig;
import io.pinecone.configs.PineconeConnection;
public class TargetIndexByHostExample {
public static void main(String[] args) {
PineconeConfig config = new PineconeConfig("YOUR_API_KEY");
config.setHost("INDEX_HOST");
PineconeConnection connection = new PineconeConnection(config);
// For the Java SDK, you must specify both the index host and name.
Index index = new Index(connection, "INDEX_NAME");
}
}
```
```go Go {21} theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
// This creates a new gRPC index connection, targeting the namespace "example-namespace"
idxConnectionNs1, err := pc.Index(pinecone.NewIndexConnParams{Host: "INDEX_HOST", Namespace: "example-namespace"})
if err != nil {
log.Fatalf("Failed to create IndexConnection for Host %v: %v", idx.Host, err)
}
// This reuses the gRPC index connection, targeting a different namespace
idxConnectionNs2 := idxConnectionNs1.WithNamespace("example-namespace2")
}
```
### Get an index host
You can get the unique DNS host for an index from the Pinecone console or the Pinecone API.
To get an index host from the Pinecone console:
1. Open the [Pinecone console](https://app.pinecone.io/organizations/-/projects).
2. Select the project containing the index.
3. Select the index.
4. Copy the URL under **HOST**.
To get an index host from the Pinecone API, use the [`describe_index`](/reference/api/latest/control-plane/describe_index) operation, which returns the index host as the `host` value:
```Python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
pc.describe_index(name="docs-example")
# Response:
# {'deletion_protection': 'disabled',
# 'dimension': 1536,
# 'host': 'docs-example-4zo0ijk.svc.us-east1-aws.pinecone.io',
# 'metric': 'cosine',
# 'name': 'docs-example',
# 'spec': {'serverless': {'cloud': 'aws', 'region': 'us-east-1'}},
# 'status': {'ready': True, 'state': 'Ready'}}
```
```JavaScript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' });
await pc.describeIndex('docs-example');
// Response:
// {
// "name": "docs-example",
// "dimension": 1536,
// "metric": "cosine",
// "host": "docs-example-4zo0ijk.svc.us-east1-aws.pinecone.io",
// "deletionProtection": "disabled",
// "spec": {
// "serverless": {
// "cloud": "aws",
// "region": "us-east-1"
// }
// },
// "status": {
// "ready": true,
// "state": "Ready"
// }
// }
```
```java Java theme={null}
import io.pinecone.clients.Pinecone;
import org.openapitools.db_control.client.model.*;
public class DescribeIndexExample {
public static void main(String[] args) {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
IndexModel indexModel = pc.describeIndex("docs-example");
System.out.println(indexModel);
}
}
// Response:
// class IndexModel {
// name: docs-example-java
// dimension: 1536
// metric: cosine
// host: docs-example-4zo0ijk.svc.us-west2-aws.pinecone.io
// deletionProtection: enabled
// spec: class IndexModelSpec {
// pod: null
// serverless: class ServerlessSpec {
// cloud: aws
// region: us-east-1
// }
// }
// status: class IndexModelStatus {
// ready: true
// state: Ready
// }
// }
```
```go Go theme={null}
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func prettifyStruct(obj interface{}) string {
bytes, _ := json.MarshalIndent(obj, "", " ")
return string(bytes)
}
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
idx, err := pc.DescribeIndex(ctx, "docs-example")
if err != nil {
log.Fatalf("Failed to describe index \"%v\": %v", idx.Name, err)
} else {
fmt.Printf("index: %v\n", prettifyStruct(idx))
}
}
// Response:
// index: {
// "name": "docs-example",
// "dimension": 1536,
// "host": "docs-example-govk0nt.svc.apw5-4e34-81fa.pinecone.io",
// "metric": "cosine",
// "deletion_protection": "disabled",
// "spec": {
// "serverless": {
// "cloud": "aws",
// "region": "us-east-1"
// }
// },
// "status": {
// "ready": true,
// "state": "Ready"
// }
// }
```
```bash curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -i -X GET "https://api.pinecone.io/indexes/docs-example-curl" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10"
# Response:
# {
# "name": "docs-example",
# "metric": "cosine",
# "dimension": 1536,
# "status": {
# "ready": true,
# "state": "Ready"
# },
# "host": "docs-example-4zo0ijk.svc.us-east1-aws.pinecone.io",
# "spec": {
# "serverless": {
# "region": "us-east-1",
# "cloud": "aws"
# }
# }
# }
```
## Target by index name
This method is convenient for testing but is not recommended for production:
```Python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
index = pc.Index("docs-example")
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' });
// For the Node.js SDK, you must specify both the index host and name.
const index = pc.index('docs-example');
```
```java Java theme={null}
import io.pinecone.clients.Index;
import io.pinecone.clients.Pinecone;
public class GenerateEmbeddings {
public static void main(String[] args) throws ApiException {
Pinecone pc = new Pinecone.Builder("YOUR_API_KEY").build();
Index index = pc.getIndexConnection("docs-example");
}
}
```
```go Go theme={null}
// It is not possible to target an index by name in the Go SDK.
// You must target an index by host.
```
# Update records
Source: https://docs.pinecone.io/guides/manage-data/update-data
Update Pinecone records by ID to change vector values or metadata, or update metadata across multiple records using a metadata filter expression.
You can [update](/reference/api/latest/data-plane/update) a single record using the record ID or multiple records using a metadata filter.
* **Update by ID**: Update a single record's metadata (add or change fields) or vector values.
* **Update by metadata**: Update metadata (add or change fields) across multiple records using a metadata filter. Vector values cannot be updated.
To update entire records, use the [upsert](/guides/index-data/upsert-data) operation instead.
Updates consume [write units (WUs)](/guides/manage-cost/understanding-cost#write-units). See [Understanding cost](/guides/manage-cost/understanding-cost#update) for how update cost is calculated.
## Update by ID
To update the vector and/or metadata of a single record, use the [`update`](/reference/api/latest/data-plane/update) operation with the following parameters:
* `namespace`: The [namespace](/guides/index-data/indexing-overview#namespaces) containing the record to update. To use the default namespace, set the namespace to `"__default__"`.
* `id`: The ID of the record to update.
* One or both of the following:
* Updated values for the vector. Specify one of the following:
* `values`: For dense vectors. Must have the same length as the existing vector.
* `sparse_values`: For sparse vectors.
* `setMetadata`: The metadata to add or change. When updating metadata, only the specified metadata fields are modified, and if a specified metadata field does not exist, it is added.
If a non-existent record ID is specified, no records are affected and a `200 OK` status is returned.
In this example, assume you are updating the dense vector values and one metadata value of the following record in the `example-namespace` namespace:
```
(
namespace="example-namespace",
id="id-3",
values=[4.0, 2.0],
setMetadata={"type": "doc", "genre": "drama"}
)
```
```Python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
index = pc.Index(host="INDEX_HOST")
index.update(
namespace="example-namespace",
id="id-3",
values=[5.0, 3.0],
set_metadata={"genre": "comedy"}
)
```
```JavaScript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({ apiKey: "YOUR_API_KEY" })
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
const index = pc.index("INDEX_NAME", "INDEX_HOST")
await index.namespace('example-namespace').update({
id: 'id-3',
values: [5.0, 3.0],
metadata: {
genre: "comedy",
},
});
```
```java Java theme={null}
import com.google.protobuf.Struct;
import com.google.protobuf.Value;
import io.pinecone.clients.Index;
import io.pinecone.configs.PineconeConfig;
import io.pinecone.configs.PineconeConnection;
import io.pinecone.proto.UpdateResponse;
import java.util.Arrays;
import java.util.List;
public class UpdateExample {
public static void main(String[] args) {
PineconeConfig config = new PineconeConfig("YOUR_API_KEY");
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
config.setHost("INDEX_HOST");
PineconeConnection connection = new PineconeConnection(config);
Index index = new Index(connection, "INDEX_NAME");
List values = Arrays.asList(5.0f, 3.0f);
Struct metaData = Struct.newBuilder()
.putFields("genre",
Value.newBuilder().setStringValue("comedy").build())
.build();
UpdateResponse updateResponse = index.update("id-3", values, metaData, "example-namespace", null, null);
System.out.println(updateResponse);
}
}
```
```go Go theme={null}
package main
import (
"context"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
"google.golang.org/protobuf/types/known/structpb"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
idxConnection, err := pc.Index(pinecone.NewIndexConnParams{Host: "INDEX_HOST", Namespace: "example-namespace"})
if err != nil {
log.Fatalf("Failed to create IndexConnection for Host: %v", err)
}
id := "id-3"
metadataMap := map[string]interface{}{
"genre": "comedy",
}
metadataFilter, err := structpb.NewStruct(metadataMap)
if err != nil {
log.Fatalf("Failed to create metadata map: %v", err)
}
err = idxConnection.UpdateVector(ctx, &pinecone.UpdateVectorRequest{
Id: id,
Values: []float32{5.0, 3.0},
Metadata: metadataFilter,
})
if err != nil {
log.Fatalf("Failed to update vector with ID %v: %v", id, err)
}
}
```
```bash curl theme={null}
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
# Update both values and metadata
curl "https://$INDEX_HOST/vectors/update" \
-H "Api-Key: $PINECONE_API_KEY" \
-H 'Content-Type: application/json' \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"id": "id-3",
"values": [5.0, 3.0],
"setMetadata": {"genre": "comedy"},
"namespace": "example-namespace"
}'
```
After the update, the dense vector values and the `genre` metadata value are changed, but the `type` metadata value is unchanged:
```
(
id="id-3",
values=[5.0, 3.0],
metadata={"type": "doc", "genre": "comedy"}
)
```
## Update by metadata
To add or change metadata across multiple records in a namespace, use the `update` operation with the following parameters:
* `namespace`: The [namespace](/guides/index-data/indexing-overview#namespaces) containing the records to update. To use the default namespace, set this to `"__default__"`.
* `filter`: A [metadata filter expression](/guides/index-data/indexing-overview#metadata-filter-expressions) to match the records to update.
* `setMetadata`: The metadata to add or change. When updating metadata, only the specified metadata fields are modified. If a specified metadata field does not exist, it is added.
* `dry_run`: Optional. If `true`, the number of records that match the filter expression is returned, but the records are not updated.
Each request updates a maximum of 100,000 records. Use `"dry_run": true` to check if you need to run the request multiple times. See the example below for details.
For example, let's say you have records that represent chunks of a single document with metadata that keeps track of chunk and document details, and you want to store the author's name with each chunk of the document:
```json theme={null}
{
"id": "document1#chunk1",
"values": [0.0236663818359375, -0.032989501953125, ..., -0.01041412353515625, 0.0086669921875],
"metadata": {
"document_id": "document1",
"document_title": "Introduction to Vector Databases",
"chunk_number": 1,
"chunk_text": "First chunk of the document content...",
"document_url": "https://example.com/docs/document1"
}
},
{
"id": "document1#chunk2",
"values": [-0.0412445068359375, 0.028839111328125, ..., 0.01953125, -0.0174560546875],
"metadata": {
"document_id": "document1",
"document_title": "Introduction to Vector Databases",
"chunk_number": 2,
"chunk_text": "Second chunk of the document content...",
"document_url": "https://example.com/docs/document1"
}
},
...
```
The following code updates all matching records with the new `author` metadata field:
```Python Python theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
index = pc.Index(host="INDEX_HOST")
# Use dry_run to check how many records match the filter
dry_run_response = index.update(
namespace="example-namespace",
filter={"document_title": {"$eq": "Introduction to Vector Databases"}},
set_metadata={"author": "Del Klein"},
dry_run=True
)
print(dry_run_response.matched_records)
# Perform the update
response = index.update(
namespace="example-namespace",
filter={"document_title": {"$eq": "Introduction to Vector Databases"}},
set_metadata={"author": "Del Klein"}
)
```
```JavaScript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone'
const pc = new Pinecone({ apiKey: "YOUR_API_KEY" })
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
const index = pc.index("INDEX_NAME", "INDEX_HOST")
await index.namespace('example-namespace').update({
filter: { document_title: { $eq: 'Introduction to Vector Databases' } },
metadata: { author: 'Del Klein' },
});
```
```java Java theme={null}
import com.google.protobuf.Struct;
import com.google.protobuf.Value;
import io.pinecone.clients.Index;
import io.pinecone.configs.PineconeConfig;
import io.pinecone.configs.PineconeConnection;
import io.pinecone.proto.UpdateResponse;
public class UpdateByMetadataExample {
public static void main(String[] args) {
PineconeConfig config = new PineconeConfig("YOUR_API_KEY");
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
config.setHost("INDEX_HOST");
PineconeConnection connection = new PineconeConnection(config);
Index index = new Index(connection, "INDEX_NAME");
Struct filter = Struct.newBuilder()
.putFields("document_title", Value.newBuilder()
.setStructValue(Struct.newBuilder()
.putFields("$eq", Value.newBuilder()
.setStringValue("Introduction to Vector Databases")
.build())
.build())
.build())
.build();
Struct metadata = Struct.newBuilder()
.putFields("author", Value.newBuilder()
.setStringValue("Del Klein")
.build())
.build();
// Dry run to check how many records match
UpdateResponse dryRunResponse = index.updateByMetadata(
filter, metadata, "example-namespace", true);
System.out.println("Matched records: " + dryRunResponse.getMatchedRecords());
// Perform the update
UpdateResponse response = index.updateByMetadata(
filter, metadata, "example-namespace");
System.out.println(response);
}
}
```
```go Go theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
"google.golang.org/protobuf/types/known/structpb"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
// To get the unique host for an index,
// see https://docs.pinecone.io/guides/manage-data/target-an-index
idxConnection, err := pc.Index(pinecone.NewIndexConnParams{
Host: "INDEX_HOST",
Namespace: "example-namespace",
})
if err != nil {
log.Fatalf("Failed to create IndexConnection for Host: %v", err)
}
filter, err := structpb.NewStruct(map[string]interface{}{
"document_title": map[string]interface{}{
"$eq": "Introduction to Vector Databases",
},
})
if err != nil {
log.Fatalf("Failed to create filter: %v", err)
}
metadata, err := structpb.NewStruct(map[string]interface{}{
"author": "Del Klein",
})
if err != nil {
log.Fatalf("Failed to create metadata: %v", err)
}
// Dry run to check how many records match
dryRun := true
dryRunRes, err := idxConnection.UpdateVectorsByMetadata(ctx, &pinecone.UpdateVectorsByMetadataRequest{
Filter: filter,
Metadata: metadata,
DryRun: &dryRun,
})
if err != nil {
log.Fatalf("Failed to dry run update: %v", err)
}
fmt.Printf("Matched records: %d\n", dryRunRes.MatchedRecords)
// Perform the update
res, err := idxConnection.UpdateVectorsByMetadata(ctx, &pinecone.UpdateVectorsByMetadataRequest{
Filter: filter,
Metadata: metadata,
})
if err != nil {
log.Fatalf("Failed to update vectors by metadata: %v", err)
}
fmt.Printf("Updated records: %d\n", res.MatchedRecords)
}
```
```bash curl theme={null}
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
curl "https://$INDEX_HOST/vectors/update" \
-H "Api-Key: $PINECONE_API_KEY" \
-H 'Content-Type: application/json' \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"namespace": "example-namespace",
"filter": {
"document_title": {"$eq": "Introduction to Vector Databases"}
},
"setMetadata": {
"author": "Del Klein"
}
}'
```
### Handling large updates
If you need to update most of the records in a large namespace, [contact Support](https://app.pinecone.io/organizations/-/settings/support/ticket) for help creating an export to enable a faster and more cost-effective approach.
Each request updates a maximum of 100,000 records. For larger datasets, use `dry_run` to check the count and repeat the request as needed:
1. To check how many records match the filter expression, send a request with `dry_run` set to `true`:
```bash curl {11} theme={null}
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
curl "https://$INDEX_HOST/vectors/update" \
-H "Api-Key: $PINECONE_API_KEY" \
-H 'Content-Type: application/json' \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"dry_run": true,
"namespace": "example-namespace",
"filter": {
"document_title": {"$eq": "Introduction to Vector Databases"}
},
"setMetadata": {
"author": "Del Klein"
}
}'
```
The response contains the number of records that match the filter expression:
```json theme={null}
{
"matchedVectors": 150000
}
```
Since this number exceeds the 100,000 record limit, you'll need to run the update request multiple times.
2. Initiate the first update by sending the request without the `dry_run` parameter:
```bash curl theme={null}
curl "https://$INDEX_HOST/vectors/update" \
-H "Api-Key: $PINECONE_API_KEY" \
-H 'Content-Type: application/json' \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"namespace": "example-namespace",
"filter": {
"document_title": {"$eq": "Introduction to Vector Databases"}
},
"setMetadata": {
"author": "Del Klein"
}
}'
```
Again, the response contains the total number of records that match the filter expression, but only 100,000 will be updated:
```json theme={null}
{
"matchedVectors": 150000
}
```
3. Pinecone is eventually consistent, so there can be a slight delay before your update request is processed. Repeat the `dry_run` request until the number of matching records shows that the first 100,000 records have been updated:
```bash curl {11} theme={null}
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
curl "https://$INDEX_HOST/vectors/update" \
-H "Api-Key: $PINECONE_API_KEY" \
-H 'Content-Type: application/json' \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"dry_run": true,
"namespace": "example-namespace",
"filter": {
"document_title": {"$eq": "Introduction to Vector Databases"}
},
"setMetadata": {
"author": "Del Klein"
}
}'
```
```json theme={null}
{
"matchedVectors": 50000
}
```
4. Once the first 100,000 records have been updated, update the remaining records:
```bash curl theme={null}
curl "https://$INDEX_HOST/vectors/update" \
-H "Api-Key: $PINECONE_API_KEY" \
-H 'Content-Type: application/json' \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"namespace": "example-namespace",
"filter": {
"document_title": {"$eq": "Introduction to Vector Databases"}
},
"setMetadata": {
"author": "Del Klein"
}
}'
```
5. Repeat the `dry_run` request until the number of matching records shows that the remaining records have been updated:
```bash curl {11} theme={null}
# To get the unique host for an index,
# see https://docs.pinecone.io/guides/manage-data/target-an-index
PINECONE_API_KEY="YOUR_API_KEY"
INDEX_HOST="INDEX_HOST"
curl "https://$INDEX_HOST/vectors/update" \
-H "Api-Key: $PINECONE_API_KEY" \
-H 'Content-Type: application/json' \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"dry_run": true,
"namespace": "example-namespace",
"filter": {
"document_title": {"$eq": "Introduction to Vector Databases"}
},
"setMetadata": {
"author": "Del Klein"
}
}'
```
```json theme={null}
{
"matchedVectors": 0
}
```
Once the request has completed, all matching records include the author name as metadata:
```json {10,22} theme={null}
{
"id": "document1#chunk1",
"values": [0.0236663818359375, -0.032989501953125, ..., -0.01041412353515625, 0.0086669921875],
"metadata": {
"document_id": "document1",
"document_title": "Introduction to Vector Databases",
"chunk_number": 1,
"chunk_text": "First chunk of the document content...",
"document_url": "https://example.com/docs/document1",
"author": "Del Klein"
}
},
{
"id": "document1#chunk2",
"values": [-0.0412445068359375, 0.028839111328125, ..., 0.01953125, -0.0174560546875],
"metadata": {
"document_id": "document1",
"document_title": "Introduction to Vector Databases",
"chunk_number": 2,
"chunk_text": "Second chunk of the document content...",
"document_url": "https://example.com/docs/document1",
"author": "Del Klein"
}
},
...
```
### Limitations
* Each request updates a maximum of 100,000 records. Use `"dry_run": true` to check if you need to run the request multiple times. See the example above for details.
* You can add or change metadata across multiple records, but you cannot remove metadata fields.
## Remove a metadata field
To remove a metadata field from a record, use the [upsert](/guides/index-data/upsert-data) operation to replace the record's metadata, providing the record's existing ID and vector values along with only the metadata you want to keep. Because upsert replaces a record's metadata in full, any fields you omit are cleared.
## Data freshness
Pinecone is eventually consistent, so there can be a slight delay before updates are visible to queries. You can [use log sequence numbers](/guides/index-data/check-data-freshness#check-the-log-sequence-number) to check whether an update request has completed.
## See also
* [Update an entire document](/guides/index-data/data-modeling#update-an-entire-document)
# Integrate with Amazon S3
Source: https://docs.pinecone.io/guides/operations/integrations/integrate-with-amazon-s3
Connect Pinecone to an Amazon S3 bucket using an IAM role to import data and export audit logs.
This feature is in [public preview](/release-notes/feature-availability) and available only on [Standard and Enterprise plans](https://www.pinecone.io/pricing/).
This page shows you how to integrate Pinecone with an Amazon S3 bucket. Once your integration is set up, you can use it to [import data](/guides/index-data/import-data) from your Amazon S3 bucket into a Pinecone index hosted on AWS, or to [export audit logs](/guides/production/configure-audit-logs) to your Amazon S3 bucket.
## Before you begin
Ensure you have the following:
* A [Pinecone account](https://app.pinecone.io/).
* An [Amazon S3 bucket](https://docs.aws.amazon.com/AmazonS3/latest/userguide/creating-buckets.html).
## 1. Create an IAM policy
In the [AWS IAM console](https://console.aws.amazon.com/iam/home):
1. In the navigation pane, click **Policies**.
2. Click **Create policy**.
3. In **Select a service** section, select **S3**.
4. Select the following actions to allow:
* `ListBucket`: Permission to list some or all of the objects in an S3 bucket. Required for [importing data](/guides/index-data/import-data) and [exporting audit logs](/guides/production/configure-audit-logs).
* `GetObject`: Permission to retrieve objects from an S3 bucket. Required for [importing data](/guides/index-data/import-data).
* `PutObject`: Permission to add an object to an S3 bucket. Required for [exporting audit logs](/guides/production/configure-audit-logs).
5. In the **Resources** section, select **Specific**.
6. For the **bucket**, specify the ARN of the bucket you created. For example: `arn:aws:s3:::example-bucket-name`
7. For the **object**, specify an object ARN as the target resource. For example: `arn:aws:s3:::example-bucket-name/*`
8. Click **Next**.
9. Specify the name of your policy. For example: "Pinecone-S3-Access".
10. Click **Create policy**.
### Targeting a subdirectory (optional)
To write [audit logs](/guides/production/configure-audit-logs) to a specific subdirectory within your S3 bucket (e.g., `my-bucket/pinecone-logs/`), you need to configure your IAM policy differently for `ListBucket` vs. object-level actions:
1. For `ListBucket`, use a **Condition** block with `StringLike` to specify the prefix. Include both the directory path with and without the trailing wildcard:
```json theme={null}
{
"Sid": "ListBucketWithPrefix",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::example-bucket-name",
"Condition": {
"StringLike": {
"s3:prefix": [
"pinecone-logs/",
"pinecone-logs/*"
]
}
}
}
```
2. For `PutObject` and `GetObject`, use the **Resource** specifier with the subdirectory path:
```json theme={null}
{
"Sid": "ObjectActionsInSubdirectory",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject"
],
"Resource": "arn:aws:s3:::example-bucket-name/pinecone-logs/*"
}
```
**Complete example policy for subdirectory access:**
```json theme={null}
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ListBucketWithPrefix",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::example-bucket-name",
"Condition": {
"StringLike": {
"s3:prefix": [
"pinecone-logs/",
"pinecone-logs/*"
]
}
}
},
{
"Sid": "ObjectActionsInSubdirectory",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject"
],
"Resource": "arn:aws:s3:::example-bucket-name/pinecone-logs/*"
}
]
}
```
The key difference is that `ListBucket` operates on the bucket resource and uses conditions to filter by prefix, while object-level actions (`PutObject`, `GetObject`) operate directly on object resources specified in the ARN.
## 2. Set up access using an IAM role
In the [AWS IAM console](https://console.aws.amazon.com/iam/home):
1. In the navigation pane, click **Roles**.
2. Click **Create role**.
3. In the **Trusted entity type** section, select **AWS account**.
4. Select **Another AWS account**.
5. Enter the Pinecone AWS VPC account ID: `713131977538`
6. Click **Next**.
7. Select the [policy you created](#1-create-an-iam-policy).
8. Click **Next**.
9. Specify the role name. For example: "Pinecone".
10. Click **Create role**.
11. Click the role you created.
12. On the **Summary** page for the role, find the **ARN**.
For example: `arn:aws:iam::123456789012:role/PineconeAccess`
13. Copy the **ARN**.
You will need to enter the ARN into Pinecone later.
## 3. Add a storage integration
This step is required for [importing data](/guides/index-data/import-data). It is not required for [storing audit logs](/guides/production/configure-audit-logs).
In the [Pinecone console](https://app.pinecone.io/organizations/-/projects), add an integration with Amazon S3..
1. Select your project.
2. Go to [**Manage > Storage integrations**](https://app.pinecone.io/organizations/-/projects/-/storage).
3. Click **Add integration**.
4. Enter a unique integration name.
5. Select **Amazon S3**.
6. Enter the **ARN** of the [IAM role you created](/guides/operations/integrations/integrate-with-amazon-s3#2-set-up-access-using-an-iam-role).
7. Click **Add integration**.
## Next steps
* [Import data](/guides/index-data/import-data) from your Amazon S3 bucket into a Pinecone index.
* [Configure audit logs](/guides/production/configure-audit-logs) to export logs to your Amazon S3 bucket.
# Integrate with Azure Blob Storage
Source: https://docs.pinecone.io/guides/operations/integrations/integrate-with-azure-blob-storage
Connect Pinecone to Azure Blob Storage using a service principal to import data into your indexes.
This feature is in [public preview](/release-notes/feature-availability) and available only on [Standard and Enterprise plans](https://www.pinecone.io/pricing/).
This page describes how to integrate Pinecone with Azure Blob Storage. After setting up an integration, you can [import data](/guides/index-data/import-data) from an Azure Blob Storage container into a Pinecone index hosted on AWS, GCP, or Azure.
## Before you begin
Ensure you have the following:
* A [Pinecone account](https://app.pinecone.io/)
* An [Azure Blob Storage container](https://learn.microsoft.com/azure/storage/blobs/storage-blobs-introduction)
## 1. Create an app registration and service principal
Pinecone uses a service principal to access your Azure Blob Storage container.
1. [Create an app registration](https://learn.microsoft.com/entra/identity-platform/quickstart-register-app) for your Pinecone integration. This automatically creates a service principal.
When creating your app registration:
* Do not specify a **Redirect URI**.
* Copy the **Application (client) ID** and the **Directory (tenant) ID**. You'll use these values when adding a storage integration in Pinecone.
2. [Create a client secret](https://learn.microsoft.com/entra/identity-platform/how-to-add-credentials?tabs=client-secret) for the service principal.
Copy the secret's **Value** (not its **ID**). You'll use this when creating a storage integration in Pinecone.
## 2. Grant access to the storage account
[Assign the service principal to your storage account](https://learn.microsoft.com/azure/storage/common/storage-auth-aad-rbac-portal#assign-azure-rbac-roles-using-the-azure-portal):
1. In the Azure portal, navigate to the subscription associated with your storage account.
2. Select **Access control (IAM)**.
3. Click **Add** > **Add role assignment**.
4. Select **Storage Blob Data Reader** or another role that has permission to list and read blobs in a container.
5. Click **Next**.
6. Select **User, group, or service principal** and click **Select members**.
7. Select the app you created in the previous step.
8. Click **Review + assign** (you may need to click this twice).
## 3. In Pinecone, add a storage integration
In the [Pinecone console](https://app.pinecone.io/organizations/-/projects), add an integration with Azure Blob Storage:
1. Select your project.
2. Go to [**Manage > Storage integrations**](https://app.pinecone.io/organizations/-/projects/-/storage).
3. Click **Add integration**.
4. Enter a unique integration name.
5. Select **Azure Blob Storage**.
6. For **Tenant ID**, **Client ID**, and **Client secret**, enter the values you copied from Azure.
7. Click **Add integration**.
## Next steps
[Import data](/guides/index-data/import-data) from your Azure Blob Storage container into your Pinecone index.
# Integrate with Google Cloud Storage
Source: https://docs.pinecone.io/guides/operations/integrations/integrate-with-google-cloud-storage
Connect Pinecone to a Google Cloud Storage bucket with a service account key to import data into your indexes.
This feature is in [public preview](/release-notes/feature-availability) and available only on [Standard and Enterprise plans](https://www.pinecone.io/pricing/).
This page shows you how to integrate Pinecone with a Google Cloud Storage (GCS) bucket. Once your integration is set up, you can use it to [import data](/guides/index-data/import-data) from your bucket into a Pinecone index hosted on AWS, GCP, or Azure.
## Before you begin
Ensure you have the following:
* A [Pinecone account](https://app.pinecone.io/)
* A [Google Cloud Storage bucket](https://cloud.google.com/storage/docs/creating-buckets)
## 1. Create a service account and key
Pinecone will use a service account to access your GCS bucket.
1. [Create a service account](https://cloud.google.com/iam/docs/service-accounts-create) for your Pinecone integration.
2. [Create a service account key](https://cloud.google.com/iam/docs/keys-create-delete#creating). Select **JSON** as the key type.
The key will be downloaded to your computer. You'll use this key when adding a storage integration in Pinecone.
## 2. Grant access to the bucket
[Add your service account as a principal to the bucket](https://cloud.google.com/storage/docs/access-control/using-iam-permissions#bucket-add).
* For the principal, use your service account email address.
* For the role, select **Storage Object Viewer** or another role that has permission to list and read objects in a bucket.
## 3. Add a storage integration
In the [Pinecone console](https://app.pinecone.io/organizations/-/projects), add an integration with Google Cloud Storage:
1. Select your project.
2. Go to [**Manage > Storage integrations**](https://app.pinecone.io/organizations/-/projects/-/storage).
3. Click **Add integration**.
4. Enter a unique integration name.
5. Select **Google Cloud Storage**.
6. Open the JSON key file for your service account.
7. Copy the contents of the key file and paste them into the **Index account key JSON** field.
8. Click **Add integration**.
## Next steps
[Import data](/guides/index-data/import-data) from your GCS bucket into your Pinecone index.
# Manage storage integrations
Source: https://docs.pinecone.io/guides/operations/integrations/manage-storage-integrations
Update or delete existing Amazon S3, Google Cloud Storage, and Azure Blob storage integrations for your Pinecone project in the console.
This feature is available on [Standard and Enterprise plans](https://www.pinecone.io/pricing/).
This page shows you how to manage storage integrations for your Pinecone project.
To set up cloud storage for integration with Pinecone, see the following guides:
* [Integrate with Amazon S3](/guides/operations/integrations/integrate-with-amazon-s3)
* [Integrate with Google Cloud Storage](/guides/operations/integrations/integrate-with-google-cloud-storage)
* [Integrate with Azure Blob Storage](/guides/operations/integrations/integrate-with-azure-blob-storage)
## Update an integration
To update information for a storage integration through the [Pinecone console](https://app.pinecone.io/organizations/-/projects), take the following steps:
1. Select your project.
2. Go to [**Manage > Storage integrations**](https://app.pinecone.io/organizations/-/projects/-/storage).
3. For the integration you want to update, click the *...* (Actions) icon.
4. Click **Manage**.
5. Update the integration details as needed.
6. Click **Add integration**.
## Delete an integration
To delete a storage integration through the [Pinecone console](https://app.pinecone.io/organizations/-/projects), take the following steps:
1. Select your project.
2. Go to [**Manage > Storage integrations**](https://app.pinecone.io/organizations/-/projects/-/storage).
3. For the integration you want to update, click the *...* (Actions) icon.
4. Click **Delete**.
5. Enter the integration name.
6. Click **Confirm deletion**.
# Local development with Pinecone Local
Source: https://docs.pinecone.io/guides/operations/local-development
Run Pinecone Local, an in-memory Docker emulator, to develop and test apps offline without an account or usage fees.
Pinecone Local is an in-memory Pinecone emulator available as a Docker image.
This page shows you how to use Pinecone Local to develop your applications locally without connecting to your Pinecone account or incurring usage or storage fees.
Pinecone Local is not suitable for production. See [Limitations](#limitations) for details.
## Limitations
Pinecone Local has the following limitations:
* Pinecone Local uses the `2025-01` API version, which is not the latest stable version.
* Pinecone Local is available in Docker only.
* Pinecone Local is an in-memory emulator and is not suitable for production. Records loaded into Pinecone Local do not persist after it is stopped.
* Pinecone Local does not authenticate client requests. API keys are ignored.
* Max number of records per index: 100,000.
Pinecone Local does not currently support the following features:
* [Import from object storage](/guides/index-data/import-data)
* [Backup/restore of serverless indexes](/guides/manage-data/backups-overview)
* [Collections for pod-based indexes](/guides/indexes/pods/understanding-collections)
* [Namespace management](/guides/manage-data/manage-namespaces)
* [Pinecone Inference](/reference/api/introduction#inference)
* [Pinecone Assistant](/guides/assistant/overview)
## 1. Start Pinecone Local
You can configure Pinecone Local as an index emulator or database emulator:
* **Index emulator** - This approach uses the `pinecone-index` Docker image to create and configure indexes on startup. This is recommended when you want to quickly experiment with reading and writing data without needing to manage the index lifecycle.
With index emulation, you can only read and write data to the indexes created at startup. You cannot create new indexes, list indexes, or run other operations that do not involve reading and writing data.
* **Database emulator** - This approach uses the `pinecone-local` Docker image to emulate Pinecone Database more broadly. This is recommended when you want to test your production app or manually create and manage indexes.
### Index emulator
Make sure [Docker](https://docs.docker.com/get-docker/) is installed and running on your local machine.
Create a `docker-compose.yaml` file that defines a service for each index that Pinecone Local should create on startup. In this file, include the `pinecone-index` Docker image, a localhost port for the index to use, and other details:
```yaml theme={null}
services:
dense-index:
image: ghcr.io/pinecone-io/pinecone-index:latest
container_name: dense-index
environment:
PORT: 5081
INDEX_TYPE: serverless
VECTOR_TYPE: dense
DIMENSION: 2
METRIC: cosine
ports:
- "5081:5081"
platform: linux/amd64
sparse-index:
image: ghcr.io/pinecone-io/pinecone-index:latest
container_name: sparse-index
environment:
PORT: 5082
INDEX_TYPE: serverless
VECTOR_TYPE: sparse
DIMENSION: 0
METRIC: dotproduct
ports:
- "5082:5082"
platform: linux/amd64
```
For each index, update the environment variables as needed:
* `PORT`: Specify the port number for the index to listen on.
* `INDEX_TYPE`: Specify the type of Pinecone index to create. Accepted values: `serverless` or `pod`.
* `VECTOR_TYPE`: Specify the [type of vectors](/guides/index-data/indexing-overview#indexes) you will store in the index. Accepted values: `dense` or `sparse`.
Sparse is supported only with serverless indexes.
* `DIMENSION`: Specify the dimension of vectors you will store in the index.
For indexes that store only sparse vectors, this must be set to `0`.
* `METRIC`: Specify the [distance metric](/guides/index-data/indexing-overview#distance-metrics) for calculating the similarity between vectors in the index. Accepted values when storing dense vectors: `cosine`, `euclidean`, or `dotproduct`. Accepted value when storing only sparse vectors: `dotproduct`.
To start Pinecone Local, run the following command:
```shell theme={null}
docker compose up -d
```
You'll see a message with details about each index.
Make sure [Docker](https://docs.docker.com/get-docker/) is installed and running on your local machine.
Download the latest `pinecone-index` Docker image:
```shell theme={null}
docker pull ghcr.io/pinecone-io/pinecone-index:latest
```
Start Pinecone Local with one or more indexes:
```shell theme={null}
docker run -d \
--name dense-index \
-e PORT=5081 \
-e INDEX_TYPE=serverless \
-e VECTOR_TYPE=dense \
-e DIMENSION=2 \
-e METRIC=cosine \
-p 5081:5081 \
--platform linux/amd64 \
ghcr.io/pinecone-io/pinecone-index:latest
```
```shell theme={null}
docker run -d \
--name sparse-index \
-e PORT=5082 \
-e INDEX_TYPE=serverless \
-e VECTOR_TYPE=sparse \
-e DIMENSION=0 \
-e METRIC=dotproduct \
-p 5082:5082 \
--platform linux/amd64 \
ghcr.io/pinecone-io/pinecone-index:latest
```
For each index, update the environment variables as needed:
* `PORT`: Specify the port number for the index to listen on.
* `INDEX_TYPE`: Specify the type of Pinecone index to create. Accepted values: `serverless` or `pod`.
* `VECTOR_TYPE`: Specify the [type of vectors](/guides/index-data/indexing-overview#indexes) you will store in the index. Accepted values: `dense` or `sparse`.
Sparse is supported only with serverless indexes.
* `DIMENSION`: Specify the dimension of vectors you will store in the index.
For indexes that store only sparse vectors, this must be set to `0`.
* `METRIC`: Specify the [distance metric](/guides/index-data/indexing-overview#distance-metrics) for calculating the similarity between vectors in the index. Accepted values when storing dense vectors: `cosine`, `euclidean`, or `dotproduct`. Accepted value when storing only sparse vectors: `dotproduct`.
### Database emulator
Make sure [Docker](https://docs.docker.com/get-docker/) is installed and running on your local machine.
Create a `docker-compose.yaml` file that defines a service for Pinecone local, including the `pinecone-local` Docker image, the host and port that Pinecone Local will run on and the range of ports that will be available for indexes:
```yaml theme={null}
services:
pinecone:
image: ghcr.io/pinecone-io/pinecone-local:latest
environment:
PORT: 5080
PINECONE_HOST: localhost
ports:
- "5080-5090:5080-5090"
platform: linux/amd64
```
To start Pinecone Local, run the following command:
```shell theme={null}
docker compose up -d
```
You'll see a message with details about the Pinecone Local instance.
Make sure [Docker](https://docs.docker.com/get-docker/) is installed and running on your local machine.
Download the latest `pinecone-local` Docker image:
```shell theme={null}
docker pull ghcr.io/pinecone-io/pinecone-local:latest
```
Start Pinecone Local:
```shell theme={null}
docker run -d \
--name pinecone-local \
-e PORT=5080 \
-e PINECONE_HOST=localhost \
-p 5080-5090:5080-5090 \
--platform linux/amd64 \
ghcr.io/pinecone-io/pinecone-local:latest
```
This command defines the host and port that Pinecone Local will run on, as well as the range of ports that will be available for indexes.
## 2. Develop your app
Running code against Pinecone Local is just like running code against your Pinecone account, with the following differences:
* Pinecone Local does not authenticate client requests. API keys are ignored.
* The latest version of Pinecone Local uses [Pinecone API version](/reference/api/versioning) `2025-01` and requires [Python SDK](/reference/sdks/python/overview) `v6.x` or later, [Node.js SDK](/reference/sdks/node/overview) `v5.x` or later, [Java SDK](/reference/sdks/java/overview) `v4.x` or later, and [Go SDK](/reference/sdks/go/overview) `v3.x` or later.
Be sure to review the [limitations](#limitations) of Pinecone Local before using it for development or testing.
**Example**
The following example assumes that you have [started Pinecone Local without indexes](/guides/operations/local-development#database-emulator). It initializes a client, creates [an index for dense vectors](/guides/index-data/indexing-overview#indexes-with-dense-vectors) and [an index for sparse vectors](/guides/index-data/indexing-overview#indexes-with-sparse-vectors), upserts records into each, checks their record counts, and queries them.
```python Python theme={null}
from pinecone.grpc import PineconeGRPC, GRPCClientConfig
from pinecone import ServerlessSpec
# Initialize a client.
# API key is required, but the value does not matter.
# Host and port of the Pinecone Local instance
# is required when starting without indexes.
pc = PineconeGRPC(
api_key="pclocal",
host="http://localhost:5080"
)
# Create two indexes, one dense and one sparse
dense_index_name = "dense-index"
sparse_index_name = "sparse-index"
if not pc.has_index(dense_index_name):
dense_index_model = pc.create_index(
name=dense_index_name,
vector_type="dense",
dimension=2,
metric="cosine",
spec=ServerlessSpec(cloud="aws", region="us-east-1"),
deletion_protection="disabled",
tags={"environment": "development"}
)
print("Index model (dense):\n", dense_index_model)
if not pc.has_index(sparse_index_name):
sparse_index_model = pc.create_index(
name=sparse_index_name,
vector_type="sparse",
metric="dotproduct",
spec=ServerlessSpec(cloud="aws", region="us-east-1"),
deletion_protection="disabled",
tags={"environment": "development"}
)
print("\nIndex model (sparse):\n", sparse_index_model)
# Target each index, disabling tls
dense_index_host = pc.describe_index(name=dense_index_name).host
dense_index = pc.Index(host=dense_index_host, grpc_config=GRPCClientConfig(secure=False))
sparse_index_host = pc.describe_index(name=sparse_index_name).host
sparse_index = pc.Index(host=sparse_index_host, grpc_config=GRPCClientConfig(secure=False))
# Upsert records into the index (dense)
dense_index.upsert(
vectors=[
{
"id": "vec1",
"values": [1.0, -2.5],
"metadata": {"genre": "drama"}
},
{
"id": "vec2",
"values": [3.0, -2.0],
"metadata": {"genre": "documentary"}
},
{
"id": "vec3",
"values": [0.5, -1.5],
"metadata": {"genre": "documentary"}
}
],
namespace="example-namespace"
)
# Upsert records into the index (sparse)
sparse_index.upsert(
namespace="example-namespace",
vectors=[
{
"id": "vec1",
"sparse_values": {
"values": [1.7958984, 0.41577148, 2.828125, 2.8027344, 2.8691406, 1.6533203, 5.3671875, 1.3046875, 0.49780273, 0.5722656, 2.71875, 3.0820312, 2.5019531, 4.4414062, 3.3554688],
"indices": [822745112, 1009084850, 1221765879, 1408993854, 1504846510, 1596856843, 1640781426, 1656251611, 1807131503, 2543655733, 2902766088, 2909307736, 3246437992, 3517203014, 3590924191]
},
"metadata": {
"chunk_text": "AAPL reported a year-over-year revenue increase, expecting stronger Q3 demand for its flagship phones.",
"category": "technology",
"quarter": "Q3"
}
},
{
"id": "vec2",
"sparse_values": {
"values": [0.4362793, 3.3457031, 2.7714844, 3.0273438, 3.3164062, 5.6015625, 2.4863281, 0.38134766, 1.25, 2.9609375, 0.34179688, 1.4306641, 0.34375, 3.3613281, 1.4404297, 2.2558594, 2.2597656, 4.8710938, 0.5605469],
"indices": [131900689, 592326839, 710158994, 838729363, 1304885087, 1640781426, 1690623792, 1807131503, 2066971792, 2428553208, 2548600401, 2577534050, 3162218338, 3319279674, 3343062801, 3476647774, 3485013322, 3517203014, 4283091697]
},
"metadata": {
"chunk_text": "Analysts suggest that AAPL'\''s upcoming Q4 product launch event might solidify its position in the premium smartphone market.",
"category": "technology",
"quarter": "Q4"
}
},
{
"id": "vec3",
"sparse_values": {
"values": [2.6875, 4.2929688, 3.609375, 3.0722656, 2.1152344, 5.78125, 3.7460938, 3.7363281, 1.2695312, 3.4824219, 0.7207031, 0.0826416, 4.671875, 3.7011719, 2.796875, 0.61621094],
"indices": [8661920, 350356213, 391213188, 554637446, 1024951234, 1640781426, 1780689102, 1799010313, 2194093370, 2632344667, 2641553256, 2779594451, 3517203014, 3543799498, 3837503950, 4283091697]
},
"metadata": {
"chunk_text": "AAPL'\''s strategic Q3 partnerships with semiconductor suppliers could mitigate component risks and stabilize iPhone production",
"category": "technology",
"quarter": "Q3"
}
}
]
)
# Check the number of records in each index
print("\nIndex stats (dense):\n", dense_index.describe_index_stats())
print("\nIndex stats (sparse):\n", sparse_index.describe_index_stats())
# Query the index (dense) with a metadata filter
dense_response = dense_index.query(
namespace="example-namespace",
vector=[3.0, -2.0],
filter={"genre": {"$eq": "documentary"}},
top_k=1,
include_values=False,
include_metadata=True
)
print("\nDense query response:\n", dense_response)
# Query the index (sparse) with a metadata filter
sparse_response = sparse_index.query(
namespace="example-namespace",
sparse_vector={
"values": [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
"indices": [767227209, 1640781426, 1690623792, 2021799277, 2152645940, 2295025838, 2443437770, 2779594451, 2956155693, 3476647774, 3818127854, 4283091697]
},
filter={
"quarter": {"$eq": "Q4"}
},
top_k=1,
include_values=False,
include_metadata=True
)
print("/nSparse query response:\n", sparse_response)
# Delete the indexes
pc.delete_index(name=dense_index_name)
pc.delete_index(name=sparse_index_name)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
// Initialize a client.
// API key is required, but the value does not matter.
// Host and port of the Pinecone Local instance
// is required when starting without indexes.
const pc = new Pinecone({
apiKey: 'pclocal',
controllerHostUrl: 'http://localhost:5080'
});
// Create two indexes, one dense and one sparse
const denseIndexName = 'dense-index';
const sparseIndexName = 'sparse-index';
const denseIndexModel = await pc.createIndex({
name: denseIndexName,
vectorType: 'dense',
dimension: 2,
metric: 'cosine',
spec: {
serverless: {
cloud: 'aws',
region: 'us-east-1'
}
},
deletionProtection: 'disabled',
tags: { environment: 'development' },
});
console.log('Index model (dense):', denseIndexModel);
const sparseIndexModel = await pc.createIndex({
name: sparseIndexName,
vectorType: 'sparse',
metric: 'dotproduct',
spec: {
serverless: {
cloud: 'aws',
region: 'us-east-1'
}
},
deletionProtection: 'disabled',
tags: { environment: 'development' },
});
console.log('\nIndex model (sparse):', sparseIndexModel);
// Target each index
const denseIndexHost = (await pc.describeIndex(denseIndexName)).host;
const denseIndex = await pc.index(denseIndexName, 'http://' + denseIndexHost);
const sparseIndexHost = (await pc.describeIndex(sparseIndexName)).host;
const sparseIndex = await pc.index(sparseIndexName, 'http://' + sparseIndexHost);
// Upsert records into the index (dense)
await denseIndex.namespace('example-namespace').upsert([
{
id: 'vec1',
values: [1.0, -2.5],
metadata: { genre: 'drama' },
},
{
id: 'vec2',
values: [3.0, -2.0],
metadata: { genre: 'documentary' },
},
{
id: 'vec3',
values: [0.5, -1.5],
metadata: { genre: 'documentary' },
}
]);
// Upsert records into the index (sparse)
await sparseIndex.namespace('example-namespace').upsert([
{
id: 'vec1',
sparseValues: {
indices: [822745112, 1009084850, 1221765879, 1408993854, 1504846510, 1596856843, 1640781426, 1656251611, 1807131503, 2543655733, 2902766088, 2909307736, 3246437992, 3517203014, 3590924191],
values: [1.7958984, 0.41577148, 2.828125, 2.8027344, 2.8691406, 1.6533203, 5.3671875, 1.3046875, 0.49780273, 0.5722656, 2.71875, 3.0820312, 2.5019531, 4.4414062, 3.3554688]
},
metadata: {
chunk_text: 'AAPL reported a year-over-year revenue increase, expecting stronger Q3 demand for its flagship phones.',
category: 'technology',
quarter: 'Q3'
}
},
{
id: 'vec2',
sparseValues: {
indices: [131900689, 592326839, 710158994, 838729363, 1304885087, 1640781426, 1690623792, 1807131503, 2066971792, 2428553208, 2548600401, 2577534050, 3162218338, 3319279674, 3343062801, 3476647774, 3485013322, 3517203014, 4283091697],
values: [0.4362793, 3.3457031, 2.7714844, 3.0273438, 3.3164062, 5.6015625, 2.4863281, 0.38134766, 1.25, 2.9609375, 0.34179688, 1.4306641, 0.34375, 3.3613281, 1.4404297, 2.2558594, 2.2597656, 4.8710938, 0.5605469]
},
metadata: {
chunk_text: "Analysts suggest that AAPL's upcoming Q4 product launch event might solidify its position in the premium smartphone market.",
category: 'technology',
quarter: 'Q4'
}
},
{
id: 'vec3',
sparseValues: {
indices: [8661920, 350356213, 391213188, 554637446, 1024951234, 1640781426, 1780689102, 1799010313, 2194093370, 2632344667, 2641553256, 2779594451, 3517203014, 3543799498, 3837503950, 4283091697],
values: [2.6875, 4.2929688, 3.609375, 3.0722656, 2.1152344, 5.78125, 3.7460938, 3.7363281, 1.2695312, 3.4824219, 0.7207031, 0.0826416, 4.671875, 3.7011719, 2.796875, 0.61621094]
},
metadata: {
chunk_text: "AAPL's strategic Q3 partnerships with semiconductor suppliers could mitigate component risks and stabilize iPhone production",
category: 'technology',
quarter: 'Q3'
}
}
]);
// Check the number of records in each index
console.log('\nIndex stats (dense):', await denseIndex.describeIndexStats());
console.log('\nIndex stats (sparse):', await sparseIndex.describeIndexStats());
// Query the index (dense) with a metadata filter
const denseQueryResponse = await denseIndex.namespace('example-namespace').query({
vector: [3.0, -2.0],
filter: {
'genre': {'$eq': 'documentary'}
},
topK: 1,
includeValues: false,
includeMetadata: true,
});
console.log('\nDense query response:', denseQueryResponse);
const sparseQueryResponse = await sparseIndex.namespace('example-namespace').query({
sparseVector: {
indices: [767227209, 1640781426, 1690623792, 2021799277, 2152645940, 2295025838, 2443437770, 2779594451, 2956155693, 3476647774, 3818127854, 4283091697],
values: [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
},
topK: 1,
includeValues: false,
includeMetadata: true
});
console.log('\nSparse query response:', sparseQueryResponse);
// Delete the index
await pc.deleteIndex(denseIndexName);
await pc.deleteIndex(sparseIndexName);
```
```java Java theme={null}
import com.google.protobuf.Struct;
import com.google.protobuf.Value;
import io.pinecone.clients.Index;
import io.pinecone.clients.Pinecone;
import io.pinecone.proto.DescribeIndexStatsResponse;
import org.openapitools.db_control.client.model.DeletionProtection;
import io.pinecone.unsigned_indices_model.QueryResponseWithUnsignedIndices;
import java.util.*;
public class PineconeLocalExample {
public static void main(String[] args) {
// Initialize a client.
// API key is required, but the value does not matter.
// When starting without indexes, disable TLS and
// provide the host and port of the Pinecone Local instance.
String host = "http://localhost:5080";
Pinecone pc = new Pinecone.Builder("pclocal")
.withHost(host)
.withTlsEnabled(false)
.build();
// Create two indexes, one dense and one sparse
String denseIndexName = "dense-index";
String sparseIndexName = "sparse-index";
HashMap tags = new HashMap<>();
tags.put("environment", "development");
pc.createServerlessIndex(
denseIndexName,
"cosine",
2,
"aws",
"us-east-1",
DeletionProtection.DISABLED,
tags
);
pc.createSparseServelessIndex(
sparseIndexName,
"aws",
"us-east-1",
DeletionProtection.DISABLED,
tags,
"sparse"
);
// Get index connection objects
Index denseIndexConnection = pc.getIndexConnection(denseIndexName);
Index sparseIndexConnection = pc.getIndexConnection(sparseIndexName);
// Upsert records into the index (dense)
Struct metaData1 = Struct.newBuilder()
.putFields("genre", Value.newBuilder().setStringValue("drama").build())
.build();
Struct metaData2 = Struct.newBuilder()
.putFields("genre", Value.newBuilder().setStringValue("documentary").build())
.build();
Struct metaData3 = Struct.newBuilder()
.putFields("genre", Value.newBuilder().setStringValue("documentary").build())
.build();
denseIndexConnection.upsert("vec1", Arrays.asList(1.0f, -2.5f), null, null, metaData1, "example-namespace");
denseIndexConnection.upsert("vec2", Arrays.asList(3.0f, -2.0f), null, null, metaData2, "example-namespace");
denseIndexConnection.upsert("vec3", Arrays.asList(0.5f, -1.5f), null, null, metaData3, "example-namespace");
// Upsert records into the index (sparse)
ArrayList indices1 = new ArrayList<>(Arrays.asList(
822745112L, 1009084850L, 1221765879L, 1408993854L, 1504846510L,
1596856843L, 1640781426L, 1656251611L, 1807131503L, 2543655733L,
2902766088L, 2909307736L, 3246437992L, 3517203014L, 3590924191L
));
ArrayList values1 = new ArrayList<>(Arrays.asList(
1.7958984f, 0.41577148f, 2.828125f, 2.8027344f, 2.8691406f,
1.6533203f, 5.3671875f, 1.3046875f, 0.49780273f, 0.5722656f,
2.71875f, 3.0820312f, 2.5019531f, 4.4414062f, 3.3554688f
));
Struct sparseMetaData1 = Struct.newBuilder()
.putFields("chunk_text", Value.newBuilder().setStringValue("AAPL reported a year-over-year revenue increase, expecting stronger Q3 demand for its flagship phones.").build())
.putFields("category", Value.newBuilder().setStringValue("technology").build())
.putFields("quarter", Value.newBuilder().setStringValue("Q3").build())
.build();
ArrayList indices2 = new ArrayList<>(Arrays.asList(
131900689L, 592326839L, 710158994L, 838729363L, 1304885087L,
1640781426L, 1690623792L, 1807131503L, 2066971792L, 2428553208L,
2548600401L, 2577534050L, 3162218338L, 3319279674L, 3343062801L,
3476647774L, 3485013322L, 3517203014L, 4283091697L
));
ArrayList values2 = new ArrayList<>(Arrays.asList(
0.4362793f, 3.3457031f, 2.7714844f, 3.0273438f, 3.3164062f,
5.6015625f, 2.4863281f, 0.38134766f, 1.25f, 2.9609375f,
0.34179688f, 1.4306641f, 0.34375f, 3.3613281f, 1.4404297f,
2.2558594f, 2.2597656f, 4.8710938f, 0.5605469f
));
Struct sparseMetaData2 = Struct.newBuilder()
.putFields("chunk_text", Value.newBuilder().setStringValue("Analysts suggest that AAPL'\\''s upcoming Q4 product launch event might solidify its position in the premium smartphone market.").build())
.putFields("category", Value.newBuilder().setStringValue("technology").build())
.putFields("quarter", Value.newBuilder().setStringValue("Q4").build())
.build();
ArrayList indices3 = new ArrayList<>(Arrays.asList(
8661920L, 350356213L, 391213188L, 554637446L, 1024951234L,
1640781426L, 1780689102L, 1799010313L, 2194093370L, 2632344667L,
2641553256L, 2779594451L, 3517203014L, 3543799498L,
3837503950L, 4283091697L
));
ArrayList values3 = new ArrayList<>(Arrays.asList(
2.6875f, 4.2929688f, 3.609375f, 3.0722656f, 2.1152344f,
5.78125f, 3.7460938f, 3.7363281f, 1.2695312f, 3.4824219f,
0.7207031f, 0.0826416f, 4.671875f, 3.7011719f, 2.796875f,
0.61621094f
));
Struct sparseMetaData3 = Struct.newBuilder()
.putFields("chunk_text", Value.newBuilder().setStringValue("AAPL'\\''s strategic Q3 partnerships with semiconductor suppliers could mitigate component risks and stabilize iPhone production").build())
.putFields("category", Value.newBuilder().setStringValue("technology").build())
.putFields("quarter", Value.newBuilder().setStringValue("Q3").build())
.build();
sparseIndexConnection.upsert("vec1", Collections.emptyList(), indices1, values1, sparseMetaData1, "example-namespace");
sparseIndexConnection.upsert("vec2", Collections.emptyList(), indices2, values2, sparseMetaData2, "example-namespace");
sparseIndexConnection.upsert("vec3", Collections.emptyList(), indices3, values3, sparseMetaData3, "example-namespace");
// Check the number of records each the index
DescribeIndexStatsResponse denseIndexStatsResponse = denseIndexConnection.describeIndexStats(null);
System.out.println("Index stats (dense):");
System.out.println(denseIndexStatsResponse);
DescribeIndexStatsResponse sparseIndexStatsResponse = sparseIndexConnection.describeIndexStats(null);
System.out.println("Index stats (sparse):");
System.out.println(sparseIndexStatsResponse);
// Query the index (dense) with a metadata filter
List queryVector = Arrays.asList(1.0f, 1.5f);
QueryResponseWithUnsignedIndices denseQueryResponse = denseIndexConnection.query(1, queryVector, null, null, null, "example-namespace", null, false, true);
System.out.println("Dense query response:");
System.out.println(denseQueryResponse);
// Query the index (sparse) with a metadata filter
List sparseIndices = Arrays.asList(
767227209L, 1640781426L, 1690623792L, 2021799277L, 2152645940L,
2295025838L, 2443437770L, 2779594451L, 2956155693L, 3476647774L,
3818127854L, 428309169L);
List sparseValues = Arrays.asList(
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f);
QueryResponseWithUnsignedIndices sparseQueryResponse = sparseIndexConnection.query(1, null, sparseIndices, sparseValues, null, "example-namespace", null, false, true);
System.out.println("Sparse query response:");
System.out.println(sparseQueryResponse);
// Delete the indexes
pc.deleteIndex(denseIndexName);
pc.deleteIndex(sparseIndexName);
}
}
```
```go Go theme={null}
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
"google.golang.org/protobuf/types/known/structpb"
)
func prettifyStruct(obj interface{}) string {
bytes, _ := json.MarshalIndent(obj, "", " ")
return string(bytes)
}
func main() {
ctx := context.Background()
// Initialize a client.
// No API key is required.
// Host and port of the Pinecone Local instance
// is required when starting without indexes.
pc, err := pinecone.NewClientBase(pinecone.NewClientBaseParams{
Host: "http://localhost:5080",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
// Create two indexes, one dense and one sparse
denseIndexName := "dense-index"
denseVectorType := "dense"
dimension := int32(2)
denseMetric := pinecone.Cosine
deletionProtection := pinecone.DeletionProtectionDisabled
denseIdx, err := pc.CreateServerlessIndex(ctx, &pinecone.CreateServerlessIndexRequest{
Name: denseIndexName,
VectorType: &denseVectorType,
Dimension: &dimension,
Metric: &denseMetric,
Cloud: pinecone.Aws,
Region: "us-east-1",
DeletionProtection: &deletionProtection,
Tags: &pinecone.IndexTags{"environment": "development"},
})
if err != nil {
log.Fatalf("Failed to create serverless index: %v", denseIdx.Name)
} else {
fmt.Printf("Successfully created serverless index: %v\n", denseIdx.Name)
}
sparseIndexName := "sparse-index"
sparseVectorType := "sparse"
sparseMetric := pinecone.Dotproduct
sparseIdx, err := pc.CreateServerlessIndex(ctx, &pinecone.CreateServerlessIndexRequest{
Name: sparseIndexName,
VectorType: &sparseVectorType,
Metric: &sparseMetric,
Cloud: pinecone.Aws,
Region: "us-east-1",
DeletionProtection: &deletionProtection,
Tags: &pinecone.IndexTags{"environment": "development"},
})
if err != nil {
log.Fatalf("Failed to create serverless index: %v", sparseIdx.Name)
} else {
fmt.Printf("\nSuccessfully created serverless index: %v\n", sparseIdx.Name)
}
// Get the index hosts
denseIdxModel, err := pc.DescribeIndex(ctx, denseIndexName)
if err != nil {
log.Fatalf("Failed to describe index \"%v\": %v", denseIndexName, err)
}
sparseIdxModel, err := pc.DescribeIndex(ctx, sparseIndexName)
if err != nil {
log.Fatalf("Failed to describe index \"%v\": %v", sparseIndexName, err)
}
// Target the indexes.
// Make sure to prefix the hosts with http:// to let the SDK know to disable tls.
denseIdxConnection, err := pc.Index(pinecone.NewIndexConnParams{Host: "http://" + denseIdxModel.Host, Namespace: "example-namespace"})
if err != nil {
log.Fatalf("Failed to create IndexConnection for Host: %v", err)
}
sparseIdxConnection, err := pc.Index(pinecone.NewIndexConnParams{Host: "http://" + sparseIdxModel.Host, Namespace: "example-namespace"})
if err != nil {
log.Fatalf("Failed to create IndexConnection for Host: %v", err)
}
// Upsert records into the index (dense)
denseMetadataMap1 := map[string]interface{}{
"genre": "drama",
}
denseMetadata1, err := structpb.NewStruct(denseMetadataMap1)
if err != nil {
log.Fatalf("Failed to create metadata map: %v", err)
}
denseMetadataMap2 := map[string]interface{}{
"genre": "documentary",
}
denseMetadata2, err := structpb.NewStruct(denseMetadataMap2)
if err != nil {
log.Fatalf("Failed to create metadata map: %v", err)
}
denseMetadataMap3 := map[string]interface{}{
"genre": "documentary",
}
denseMetadata3, err := structpb.NewStruct(denseMetadataMap3)
if err != nil {
log.Fatalf("Failed to create metadata map: %v", err)
}
denseVectors := []*pinecone.Vector{
{
Id: "vec1",
Values: &[]float32{1.0, -2.5},
Metadata: denseMetadata1,
},
{
Id: "vec2",
Values: &[]float32{3.0, -2.0},
Metadata: denseMetadata2,
},
{
Id: "vec3",
Values: &[]float32{0.5, -1.5},
Metadata: denseMetadata3,
},
}
denseCount, err := denseIdxConnection.UpsertVectors(ctx, denseVectors)
if err != nil {
log.Fatalf("Failed to upsert vectors: %v", err)
} else {
fmt.Printf("\nSuccessfully upserted %d vector(s)!\n", denseCount)
}
// Upsert records into the index (sparse)
sparseValues1 := pinecone.SparseValues{
Indices: []uint32{822745112, 1009084850, 1221765879, 1408993854, 1504846510, 1596856843, 1640781426, 1656251611, 1807131503, 2543655733, 2902766088, 2909307736, 3246437992, 3517203014, 3590924191},
Values: []float32{1.7958984, 0.41577148, 2.828125, 2.8027344, 2.8691406, 1.6533203, 5.3671875, 1.3046875, 0.49780273, 0.5722656, 2.71875, 3.0820312, 2.5019531, 4.4414062, 3.3554688},
}
sparseMetadataMap1 := map[string]interface{}{
"chunk_text": "AAPL reported a year-over-year revenue increase, expecting stronger Q3 demand for its flagship phones",
"category": "technology",
"quarter": "Q3",
}
sparseMetadata1, err := structpb.NewStruct(sparseMetadataMap1)
if err != nil {
log.Fatalf("Failed to create metadata map: %v", err)
}
sparseValues2 := pinecone.SparseValues{
Indices: []uint32{131900689, 592326839, 710158994, 838729363, 1304885087, 1640781426, 1690623792, 1807131503, 2066971792, 2428553208, 2548600401, 2577534050, 3162218338, 3319279674, 3343062801, 3476647774, 3485013322, 3517203014, 4283091697},
Values: []float32{0.4362793, 3.3457031, 2.7714844, 3.0273438, 3.3164062, 5.6015625, 2.4863281, 0.38134766, 1.25, 2.9609375, 0.34179688, 1.4306641, 0.34375, 3.3613281, 1.4404297, 2.2558594, 2.2597656, 4.8710938, 0.560546},
}
sparseMetadataMap2 := map[string]interface{}{
"chunk_text": "Analysts suggest that AAPL's upcoming Q4 product launch event might solidify its position in the premium smartphone market.",
"category": "technology",
"quarter": "Q4",
}
sparseMetadata2, err := structpb.NewStruct(sparseMetadataMap2)
if err != nil {
log.Fatalf("Failed to create metadata map: %v", err)
}
sparseValues3 := pinecone.SparseValues{
Indices: []uint32{8661920, 350356213, 391213188, 554637446, 1024951234, 1640781426, 1780689102, 1799010313, 2194093370, 2632344667, 2641553256, 2779594451, 3517203014, 3543799498, 3837503950, 4283091697},
Values: []float32{2.6875, 4.2929688, 3.609375, 3.0722656, 2.1152344, 5.78125, 3.7460938, 3.7363281, 1.2695312, 3.4824219, 0.7207031, 0.0826416, 4.671875, 3.7011719, 2.796875, 0.61621094},
}
sparseMetadataMap3 := map[string]interface{}{
"chunk_text": "AAPL's strategic Q3 partnerships with semiconductor suppliers could mitigate component risks and stabilize iPhone production",
"category": "technology",
"quarter": "Q3",
}
sparseMetadata3, err := structpb.NewStruct(sparseMetadataMap3)
if err != nil {
log.Fatalf("Failed to create metadata map: %v", err)
}
sparseVectors := []*pinecone.Vector{
{
Id: "vec1",
SparseValues: &sparseValues1,
Metadata: sparseMetadata1,
},
{
Id: "vec2",
SparseValues: &sparseValues2,
Metadata: sparseMetadata2,
},
{
Id: "vec3",
SparseValues: &sparseValues3,
Metadata: sparseMetadata3,
},
}
sparseCount, err := sparseIdxConnection.UpsertVectors(ctx, sparseVectors)
if err != nil {
log.Fatalf("Failed to upsert vectors: %v", err)
} else {
fmt.Printf("\nSuccessfully upserted %d vector(s)!\n", sparseCount)
}
// Check the number of records in each index
denseStats, err := denseIdxConnection.DescribeIndexStats(ctx)
if err != nil {
log.Fatalf("Failed to describe index: %v", err)
} else {
fmt.Printf("\nIndex stats (dense): %+v\n", prettifyStruct(*denseStats))
}
sparseStats, err := sparseIdxConnection.DescribeIndexStats(ctx)
if err != nil {
log.Fatalf("Failed to describe index: %v", err)
} else {
fmt.Printf("\nIndex stats (sparse): %+v\n", prettifyStruct(*sparseStats))
}
// Query the index (dense) with a metadata filter
queryVector := []float32{3.0, -2.0}
queryMetadataMap := map[string]interface{}{
"genre": map[string]interface{}{
"$eq": "documentary",
},
}
metadataFilter, err := structpb.NewStruct(queryMetadataMap)
if err != nil {
log.Fatalf("Failed to create metadata map: %v", err)
}
denseRes, err := denseIdxConnection.QueryByVectorValues(ctx, &pinecone.QueryByVectorValuesRequest{
Vector: queryVector,
TopK: 1,
MetadataFilter: metadataFilter,
IncludeValues: false,
IncludeMetadata: true,
})
if err != nil {
log.Fatalf("Error encountered when querying by vector: %v", err)
} else {
fmt.Printf("\nDense query response: %v\n", prettifyStruct(denseRes))
}
// Query the index (sparse) with a metadata filter
sparseValues := pinecone.SparseValues{
Indices: []uint32{767227209, 1640781426, 1690623792, 2021799277, 2152645940, 2295025838, 2443437770, 2779594451, 2956155693, 3476647774, 3818127854, 4283091697},
Values: []float32{1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0},
}
sparseRes, err := sparseIdxConnection.QueryByVectorValues(ctx, &pinecone.QueryByVectorValuesRequest{
SparseValues: &sparseValues,
TopK: 1,
IncludeValues: false,
IncludeMetadata: true,
})
if err != nil {
log.Fatalf("Error encountered when querying by vector: %v", err)
} else {
fmt.Printf("\nSparse query response: %v\n", prettifyStruct(sparseRes))
}
// Delete the indexes
err = pc.DeleteIndex(ctx, denseIndexName)
if err != nil {
log.Fatalf("Failed to delete index: %v", err)
} else {
fmt.Printf("\nIndex \"%v\" deleted successfully\n", denseIndexName)
}
err = pc.DeleteIndex(ctx, sparseIndexName)
if err != nil {
log.Fatalf("Failed to delete index: %v", err)
} else {
fmt.Printf("\nIndex \"%v\" deleted successfully\n", sparseIndexName)
}
}
```
```shell curl theme={null}
PINECONE_LOCAL_HOST="localhost:5080"
DENSE_INDEX_HOST="localhost:5081"
SPARSE_INDEX_HOST="localhost:5082"
# Create two indexes, one dense and one sparse
curl -X POST "http://$PINECONE_LOCAL_HOST/indexes" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"name": "dense-index",
"vector_type": "dense",
"dimension": 2,
"metric": "cosine",
"spec": {
"serverless": {
"cloud": "aws",
"region": "us-east-1"
}
},
"tags": {
"environment": "development"
},
"deletion_protection": "disabled"
}'
curl -X POST "http://$PINECONE_LOCAL_HOST/indexes" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"name": "sparse-index",
"vector_type": "sparse",
"metric": "dotproduct",
"spec": {
"serverless": {
"cloud": "aws",
"region": "us-east-1"
}
},
"tags": {
"environment": "development"
},
"deletion_protection": "disabled"
}'
# Upsert records into the index (dense)
curl -X POST "http://$DENSE_INDEX_HOST/vectors/upsert" \
-H "Content-Type: application/json" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"namespace": "example-namespace",
"vectors": [
{
"id": "vec1",
"values": [1.0, -2.5],
"metadata": {"genre": "drama"}
},
{
"id": "vec2",
"values": [3.0, -2.0],
"metadata": {"genre": "documentary"}
},
{
"id": "vec3",
"values": [0.5, -1.5],
"metadata": {"genre": "documentary"}
}
]
}'
# Upsert records into the index (sparse)
curl -X POST "http://$SPARSE_INDEX_HOST/vectors/upsert" \
-H "Content-Type: application/json" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"namespace": "example-namespace",
"vectors": [
{
"id": "vec1",
"sparseValues": {
"values": [1.7958984, 0.41577148, 2.828125, 2.8027344, 2.8691406, 1.6533203, 5.3671875, 1.3046875, 0.49780273, 0.5722656, 2.71875, 3.0820312, 2.5019531, 4.4414062, 3.3554688],
"indices": [822745112, 1009084850, 1221765879, 1408993854, 1504846510, 1596856843, 1640781426, 1656251611, 1807131503, 2543655733, 2902766088, 2909307736, 3246437992, 3517203014, 3590924191]
},
"metadata": {
"chunk_text": "AAPL reported a year-over-year revenue increase, expecting stronger Q3 demand for its flagship phones.",
"category": "technology",
"quarter": "Q3"
}
},
{
"id": "vec2",
"sparseValues": {
"values": [0.4362793, 3.3457031, 2.7714844, 3.0273438, 3.3164062, 5.6015625, 2.4863281, 0.38134766, 1.25, 2.9609375, 0.34179688, 1.4306641, 0.34375, 3.3613281, 1.4404297, 2.2558594, 2.2597656, 4.8710938, 0.5605469],
"indices": [131900689, 592326839, 710158994, 838729363, 1304885087, 1640781426, 1690623792, 1807131503, 2066971792, 2428553208, 2548600401, 2577534050, 3162218338, 3319279674, 3343062801, 3476647774, 3485013322, 3517203014, 4283091697]
},
"metadata": {
"chunk_text": "Analysts suggest that AAPL'\''s upcoming Q4 product launch event might solidify its position in the premium smartphone market.",
"category": "technology",
"quarter": "Q4"
}
},
{
"id": "vec3",
"sparseValues": {
"values": [2.6875, 4.2929688, 3.609375, 3.0722656, 2.1152344, 5.78125, 3.7460938, 3.7363281, 1.2695312, 3.4824219, 0.7207031, 0.0826416, 4.671875, 3.7011719, 2.796875, 0.61621094],
"indices": [8661920, 350356213, 391213188, 554637446, 1024951234, 1640781426, 1780689102, 1799010313, 2194093370, 2632344667, 2641553256, 2779594451, 3517203014, 3543799498, 3837503950, 4283091697]
},
"metadata": {
"chunk_text": "AAPL'\''s strategic Q3 partnerships with semiconductor suppliers could mitigate component risks and stabilize iPhone production",
"category": "technology",
"quarter": "Q3"
}
}
]
}'
# Check the number of records in each index
curl -X POST "http://$DENSE_INDEX_HOST/describe_index_stats" \
-H "Content-Type: application/json" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{}'
curl -X POST "http://$SPARSE_INDEX_HOST/describe_index_stats" \
-H "Content-Type: application/json" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{}'
# Query the index (dense) with a metadata filter
curl "http://$DENSE_INDEX_HOST/query" \
-H "Content-Type: application/json" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"vector": [3.0, -2.0],
"filter": {"genre": {"$eq": "documentary"}},
"topK": 1,
"includeMetadata": true,
"includeValues": false,
"namespace": "example-namespace"
}'
# Query the index (sparse) with a metadata filter
curl "http://$SPARSE_INDEX_HOST/query" \
-H "Content-Type: application/json" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"sparseVector": {
"values": [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
"indices": [767227209, 1640781426, 1690623792, 2021799277, 2152645940, 2295025838, 2443437770, 2779594451, 2956155693, 3476647774, 3818127854, 4283091697]
},
"filter": {"quarter": {"$eq": "Q4"}},
"namespace": "example-namespace",
"topK": 1,
"includeMetadata": true,
"includeValues": false
}'
# Delete the index
curl -X DELETE "http://$PINECONE_LOCAL_HOST/indexes/dense-index" \
-H "X-Pinecone-Api-Version: 2025-10"
curl -X DELETE "http://$PINECONE_LOCAL_HOST/indexes/sparse-index" \
-H "X-Pinecone-Api-Version: 2025-10"
```
## 3. Stop Pinecone Local
Pinecone Local is an in-memory emulator. Records loaded into Pinecone Local do not persist after Pinecone Local is stopped.
To stop and remove the resources for Pinecone Local, run the following command:
```shell Docker Compose theme={null}
docker compose down
```
```shell Docker CLI theme={null}
# If you started Pinecone Local with indexes:
docker stop dense-index sparse-index
docker rm dense-index sparse-index
# If you started Pinecone Local without indexes:
docker stop pinecone-local
docker rm pinecone-local
```
## Moving from Pinecone Local to your Pinecone account
When you're ready to run your application against your Pinecone account, be sure to do the following:
* Update your application to [use your Pinecone API key](/reference/api/authentication).
* Update your application to [target your Pinecone indexes](/guides/manage-data/target-an-index).
* [Use Pinecone's import feature](/guides/index-data/import-data) to efficiently load large amounts of data into your indexes and then [use batch upserts](/guides/index-data/upsert-data#upsert-in-batches) for ongoing writes.
* Follow Pinecone's [production best practices](/guides/production/production-checklist).
# Use the Pinecone MCP server
Source: https://docs.pinecone.io/guides/operations/mcp-server
Connect AI agents to Pinecone through the MCP server to search docs, manage indexes, and query data from Claude, Cursor, Antigravity, or Claude Code.
The Pinecone MCP server enables AI agents to interact directly with Pinecone's functionality and documentation via the standardized [Model Context Protocol (MCP)](https://modelcontextprotocol.io/). Using the MCP server, agents can search Pinecone documentation, manage indexes, upsert data, and query indexes for relevant information.
This page shows you how to configure [Antigravity](https://antigravity.google/), [Claude Desktop](https://claude.ai/download), [Claude Code](https://claude.ai/code), and [Cursor](https://www.cursor.com/) to connect with the Pinecone MCP server.
Pinecone also provides a dedicated MCP server for each [Pinecone Assistant](/guides/assistant/overview), giving AI agents direct access to context from that assistant's uploaded files. The assistant MCP server is available as a managed remote endpoint or as a self-hosted Docker container that you can extend and run in your own infrastructure. See [Use an Assistant MCP server](/guides/assistant/mcp-server).
Pinecone also offers plugins and extensions with built-in skills for agentic IDEs and CLIs. See [Agentic IDEs and CLIs](/guides/get-started/ai-coding-tools) for an overview, or jump directly to the [Claude Code plugin](/integrations/claude-code), [Gemini CLI extension](/integrations/gemini-cli), [Cursor plugin](/integrations/cursor), or [Agent Skills](/integrations/agent-skills) for GitHub Copilot and other IDEs.
## Tools
The Pinecone MCP server provides the following tools:
* `search-docs`: Search the official Pinecone documentation.
* `list-indexes`: Lists all Pinecone indexes.
* `describe-index`: Describes the configuration of an index.
* `describe-index-stats`: Provides statistics about the data in the index, including the number of records and available namespaces.
* `create-index-for-model`: Creates a new index that uses an integrated inference model to embed text as vectors.
* `upsert-records`: Inserts or updates records in an index with integrated inference.
* `search-records`: Searches for records in an index based on a text query, using integrated inference for embedding. Has options for metadata filtering and reranking.
* `cascading-search`: Searches for records across multiple indexes, deduplicating and reranking the results.
* `rerank-documents`: Reranks a collection of records or text documents using a specialized reranking model.
The Pinecone MCP supports only [indexes with integrated embedding](/guides/index-data/indexing-overview#vector-embedding). Indexes for vectors you create with external embedding models are not supported.
## Before you begin
Ensure you have the following:
* A [Pinecone API key](https://app.pinecone.io/organizations/-/keys)
* [Node.js](https://nodejs.org/en) installed, with `node` and `npx` available on your `PATH`
## Configure Antigravity
Antigravity supports MCP via its built-in MCP Store. You can install the Pinecone server from the store or add it via the raw config.
**Install from the MCP Store**
1. Open the **MCP Store** via the "..." dropdown at the top of the editor's agent panel.
2. Find **Pinecone** in the list of supported servers and click **Install**.
3. Follow the on-screen prompts to authenticate and set your Pinecone API key.
**Add via raw config**
1. Open the MCP Store via the "..." dropdown at the top of the editor's agent panel.
2. Click **Manage MCP Servers**, then **View raw config**.
3. Edit `mcp_config.json` and add the Pinecone server:
```json theme={null}
{
"mcpServers": {
"pinecone": {
"command": "npx",
"args": [
"-y", "@pinecone-database/mcp"
],
"env": {
"PINECONE_API_KEY": "{{YOUR_API_KEY}}"
}
}
}
}
```
Replace `YOUR_API_KEY` with your [Pinecone API key](https://app.pinecone.io/organizations/-/keys).
After installing or saving the config, the Pinecone server and its tools should appear in the agent panel. Use the MCP tools list to confirm the server is connected.
In the agent chat, try prompts that use Pinecone. For example, try generating code that creates an index, upserts records, or searches the index. The AI can use the connected MCP server for context and actions.
## Configure Claude Code
For the easiest setup, install the [Pinecone Claude Code plugin](/integrations/claude-code) instead — it bundles the MCP server, 8 skills, and slash commands. The manual configuration below is for users who only want the MCP server.
Run the following command to add the Pinecone MCP server to your Claude Code instance:
```bash theme={null}
claude mcp add-json pinecone-mcp \
'{"type": "stdio",
"command": "npx",
"args": ["-y", "@pinecone-database/mcp"],
"env": {"PINECONE_API_KEY": "YOUR_API_KEY"}}'
```
Restart Claude Code. Then, run the `/mcp` command to check the status of the Pinecone MCP. You should see the following:
```bash theme={null}
> /mcp
⎿ MCP Server Status
• pinecone-mcp: ✓ connected
```
Test the Pinecone MCP server with prompts to Claude Code that require the server to generate Pinceone-compatible code and perform tasks in your Pinecone account.
Generate code:
> Write a Python script that creates an index for dense vectors with integrated embedding, upserts 20 sentences about dogs, waits 10 seconds, searches the index, and reranks the results.
Perform tasks:
> Create an index for dense vectors with integrated embedding, upsert 20 sentences about dogs, waits 10 seconds, search the index, and reranks the results.
## Configure Claude Desktop
Go to **Settings > Developer > Edit Config** and add the following configuration:
```json theme={null}
{
"mcpServers": {
"pinecone": {
"command": "npx",
"args": [
"-y", "@pinecone-database/mcp"
],
"env": {
"PINECONE_API_KEY": "YOUR_API_KEY"
}
}
}
}
```
Replace `YOUR_API_KEY` with your Pinecone API key.
Restart Claude Desktop. On the new chat screen, you should see a hammer (MCP) icon appear with the new MCP tools available.
Test the Pinecone MCP server with prompts that required the server to generate Pinceone-compatible code and perform tasks in your Pinecone account.
Generate code:
> Write a Python script that creates an index for dense vectors with integrated embedding, upserts 20 sentences about dogs, waits 10 seconds, searches the index, and reranks the results.
Perform tasks:
> Create an index for dense vectors with integrated embedding, upsert 20 sentences about dogs, waits 10 seconds, search the index, and reranks the results.
## Configure Cursor
For the easiest setup, install the [Pinecone Cursor plugin](/integrations/cursor) instead — it bundles the MCP server, 8 skills, and slash commands. The manual configuration below is for users who only want the MCP server.
In your project root, create a `.cursor/mcp.json` file, if it doesn't exist, and add the following configuration:
```json theme={null}
{
"mcpServers": {
"pinecone": {
"command": "npx",
"args": [
"-y", "@pinecone-database/mcp"
],
"env": {
"PINECONE_API_KEY": "{{YOUR_API_KEY}}"
}
}
}
}
```
Go to **Cursor Settings > MCP**. You should see the server and its list of tools.
The Pinecone MCP server works well out of the box. However, you can add explicit rules to ensure the server behaves as you expect.
In your project root, create a `.cursor/rules/pinecone.mdc` file and add the following:
```mdx [expandable] theme={null}
### Tool Usage for Code Generation
- When generating code related to Pinecone, always use the `pinecone` MCP and the `search_docs` tool.
- Perform at least two distinct searches per request using different, relevant questions to ensure comprehensive context is gathered before writing code.
### Error Handling
- If an error occurs while executing Pinecone-related code, immediately invoke the `pinecone` MCP and the `search_docs` tool.
- Search for guidance on the specific error encountered and incorporate any relevant findings into your resolution strategy.
### Syntax and Version Accuracy
- Before writing any code, verify and use the correct syntax for the latest stable version of the Pinecone SDK.
- Prefer official code snippets and examples from documentation over generated or assumed field values.
- Do not fabricate field names, parameter values, or request formats.
### SDK Installation Best Practices
- When providing installation instructions, always reference the current official package name.
- For Pinecone, use `pip install pinecone` not deprecated packages like `pinecone-client`.
```
Press `Command + i` to open the Agent chat. Test the Pinecone MCP server with prompts that required the server to generate Pinceone-compatible code and perform tasks in your Pinecone account.
Generate code:
> Write a Python script that creates an index for dense vectors with integrated embedding, upserts 20 sentences about dogs, waits 10 seconds, searches the index, and reranks the results.
Perform tasks:
> Create an index for dense vectors with integrated embedding, upsert 20 sentences about dogs, waits 10 seconds, search the index, and reranks the results.
# Decrease latency
Source: https://docs.pinecone.io/guides/optimize/decrease-latency
Reduce query and upsert latency in Pinecone using namespaces, metadata filters, targeting indexes by host, and regional colocation strategies.
## Use namespaces
When you divide records into [namespaces](/guides/index-data/indexing-overview#namespaces) in a logical way, you speed up queries by ensuring only relevant records are scanned. The same applies to [fetching records](/guides/manage-data/fetch-data), [listing record IDs](/guides/manage-data/list-record-ids), and other data operations.
## Filter by metadata
In addition to increasing search accuracy and relevance, [searching with metadata filters](/guides/search/filter-by-metadata) can also help decrease latency by retrieving only records that match the filter.
## Target indexes by host
When you target an index by name for data operations such as `upsert` and `query`, the SDK gets the unique DNS host for the index using the `describe_index` operation. This is convenient for testing but should be avoided in production because `describe_index` uses a different API than data operations and therefore adds an additional network call and point of failure. Instead, you should get an index host once and cache it for reuse or specify the host directly.
You can get index hosts in the [Pinecone console](https://app.pinecone.io/organizations/-/projects/-/indexes) or using the [`describe_index`](/guides/manage-data/manage-indexes#describe-an-index) operation.
The following example shows how to target an index by host directly:
When using Private Endpoints for private connectivity between your application and Pinecone, you must target the index using the [Private Endpoint URL](/guides/production/configure-private-endpoints#read-and-write-data) for the host.
```Python Python {5} theme={null}
from pinecone.grpc import PineconeGRPC as Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
index = pc.Index(host="INDEX_HOST")
```
```javascript JavaScript {6} theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' });
// For the Node.js SDK, you must specify both the index host and name.
const index = pc.index("INDEX_NAME", "INDEX_HOST");
```
```java Java {11} theme={null}
import io.pinecone.clients.Index;
import io.pinecone.configs.PineconeConfig;
import io.pinecone.configs.PineconeConnection;
public class TargetIndexByHostExample {
public static void main(String[] args) {
PineconeConfig config = new PineconeConfig("YOUR_API_KEY");
config.setHost("INDEX_HOST");
PineconeConnection connection = new PineconeConnection(config);
// For the Java SDK, you must specify both the index host and name.
Index index = new Index(connection, "INDEX_NAME");
}
}
```
```go Go {21} theme={null}
package main
import (
"context"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
idxConnection, err := pc.Index(pinecone.NewIndexConnParams{Host: "INDEX_HOST", Namespace: "example-namespace"})
if err != nil {
log.Fatalf("Failed to create IndexConnection for Host %v: %v", idx.Host, err)
}
}
```
## Reuse connections
When you target an index for upserting or querying, the client establishes a TCP connection, which is a three-step process. To avoid going through this process on every request, and reduce average request latency, [cache and reuse the index connection object](/reference/api/authentication#initialize-a-client) whenever possible.
## Use a cloud environment
If you experience slow uploads or high query latencies, it might be because you are accessing Pinecone from your home network. To decrease latency, access Pinecone/deploy your application from a cloud environment instead, ideally from the same [cloud and region](/guides/index-data/create-an-index#cloud-regions) as your index.
## Avoid batching queries
If you're batching queries, try reducing the number of queries per call to a single query vector. You can run these [queries in parallel](/guides/search/semantic-search#parallel-queries) and expect roughly the same performance as with batching.
## Avoid including vector values when not needed
Including vector values increases response size -- especially with higher `top_k` values —- which can elevate round-trip latency. If you don't need the vector values in your response, set `include_values=false` to improve query performance. This applies to [`query`](/reference/api/latest/data-plane/query) and [`fetch`](/reference/api/latest/data-plane/fetch) operations.
On-demand indexes retrieve vector values from object storage, so `fetch` operations and queries with `include_values=true` may occasionally experience higher tail latency before values are cached on disk. DRN indexes cache values locally and are not affected.
## Work with database limits
Pinecone has [rate limits](/reference/api/database-limits#rate-limits) to protect your applications and maintain infrastructure health. Rate limits vary based on pricing plan and apply to serverless indexes only.
Indexes built on [Dedicated Read Nodes](/guides/index-data/dedicated-read-nodes) are not subject to read unit limits for query, fetch, and list operations. For sizing and capacity planning guidance, see the [Dedicated Read Nodes](/guides/index-data/dedicated-read-nodes) guide.
To handle rate limits effectively:
* [Implement retry logic with exponential backoff](/guides/production/error-handling#handle-rate-limits-429).
* If you need higher limits for your use case, [contact Support](https://app.pinecone.io/organizations/-/settings/support/ticket). Most limits can be adjusted to accommodate your scaling needs.
# Increase search relevance
Source: https://docs.pinecone.io/guides/optimize/increase-relevance
Improve Pinecone search quality with reranking models, metadata filtering, and hybrid search that combines full-text and vector retrieval for RAG.
This page describes helpful techniques for improving search accuracy and relevance.
## Rerank results
[Reranking](/guides/search/rerank-results) is used as part of a two-stage vector retrieval process to improve the quality of results. You first query an index for a given number of relevant results, and then you send the query and results to a reranking model. The reranking model scores the results based on their semantic relevance to the query and returns a new, more accurate ranking. This approach is one of the simplest methods for improving quality in retrieval augmented generation (RAG) pipelines.
Pinecone provides [hosted reranking models](/guides/search/rerank-results#reranking-models) so it's easy to manage two-stage vector retrieval on a single platform. You can use a hosted model to rerank results as an integrated part of a query, or you can use a hosted model to rerank results as a standalone operation.
## Filter by metadata
Every [record](/guides/get-started/concepts#record) in an index must contain an ID and a dense or sparse vector, depending on the [type of index](/guides/index-data/indexing-overview#indexes). In addition, you can include metadata key-value pairs to store related information or context. When you search the index, you can then include a metadata filter to limit the search to records matching a filter expression.
For example, if an index contains records about books, you could use a metadata field to associate each record with a genre, like `"genre": "fiction"` or `"genre": "poetry"`. When you query the index, you could then use a metadata filter to limit your search to records related to a specific genre.
For more details, see [Filter by metadata](/guides/search/filter-by-metadata).
## Use full-text search for keyword matching
When relevance depends on exact keyword or phrase matches over text content — for example, product names, technical IDs, named entities, or jargon — we recommend [full-text search](/guides/search/full-text-search). It uses **BM25** ranking on `string` fields you've declared with `full_text_search` enabled and supports Lucene query syntax (`query_string`), including phrase, boolean, and proximity operators, plus the `$match_phrase` filter for exact phrase matching against text fields.
An index with a document schema can also include `dense_vector` and `sparse_vector` fields in the same schema, so you can combine BM25 token matching with semantic or sparse-vector ranking on a single index. A single search request ranks by one scoring type — restrict a `dense_vector` or `sparse_vector` search with a text-match filter (`$match_phrase`, `$match_all`, `$match_any`) on an FTS-enabled `string` field, or run BM25 and dense (or sparse) searches separately and merge the results client-side.
For more details, see [Full-text search](/guides/search/full-text-search).
## Match the query and passage embedding paths
When you use [integrated embedding](/guides/index-data/indexing-overview#integrated-embedding) with a model like [`llama-text-embed-v2`](/models/llama-text-embed-v2) or [`multilingual-e5-large`](/models/multilingual-e5-large), Pinecone embeds upserted data with the `passage` input type and embeds query text with the `query` input type. The encoder is the same, but the input type changes the resulting vector, so the *same* string embedded as a query and as a passage produces two different vectors. This is intentional in E5- and Llama-style models: the asymmetry is what makes a short query match a longer, semantically related passage.
A common consequence is that searching by text for the exact string you upserted does not return a similarity score near `1.0`. For example, querying for the exact text `"JetBlue Flights and Extras"` against a record containing that same text can score around `0.58`, while searching by the raw passage vector for the same record scores near `1.0`. The text query takes the `query` path and the stored record was embedded via the `passage` path, so the two vectors are not identical.
**Is a low score expected for identical short strings?** Yes. The query/passage split has the largest effect on short, low-semantic text such as exact names, error codes, SKUs, and IDs, where there is little meaning for the model to align across the two paths. Scores in roughly the `0.5`–`0.8` range for identical short strings are normal. The asymmetry helps on true semantic search (a short question matched to a longer answer passage) and only looks like a problem on exact-token-match workloads.
**When should you query through the passage path?** Only when the workload is exact or near-exact lookup (IDs, error logs, product names) rather than semantic search, and you want exact matches to score near `1.0`. You can override the read-time input type at the index level with [`configure_index`](/reference/api/latest/control-plane/configure_index). Set `model` and `field_map` to the index's existing values, and set `read_parameters.input_type` to `passage`:
```python Python theme={null}
from pinecone import Pinecone
pc = Pinecone(api_key="YOUR_API_KEY")
pc.configure_index(
name="docs-example",
embed={
"model": "llama-text-embed-v2",
"field_map": {"text": "chunk_text"},
"read_parameters": {"input_type": "passage"}
}
)
```
Note the trade-offs:
* This setting degrades true semantic search, since queries no longer use the input type the model was trained to expect.
* It applies to the whole index. With integrated inference you cannot choose `query` or `passage` per request. If you need that control, embed text yourself with the [Inference API](/reference/api/latest/inference/generate-embeddings) and search with the [`query`](/reference/api/latest/data-plane/query) operation using your own vectors.
For pure exact-match retrieval, a [sparse index](/guides/index-data/indexing-overview#indexes-with-sparse-vectors) or [full-text search](/guides/search/full-text-search) is usually a better fit than forcing dense embeddings through the passage path. See [Use full-text search for keyword matching](#use-full-text-search-for-keyword-matching) above for when keyword and phrase matching is the right tool.
## Use hybrid search
When you have both dense and sparse vectors for the same records and want to combine semantic and lexical signals at query time, you can use hybrid search. [Semantic search](/guides/search/semantic-search) can miss results based on exact keyword matches, especially in scenarios involving domain-specific terminology, while sparse-vector [lexical search](/guides/search/lexical-search) can miss results based on relationships, such as synonyms and paraphrases. Hybrid search combines the two.
There are two ways to do this:
* [Use a single index for dense and sparse vectors](/guides/search/hybrid-search#use-a-single-index-for-dense-and-sparse-vectors). This is the **recommended** approach for most use cases because you make requests to a single index, the linkage between dense and sparse vectors is implicit, and you can perform hybrid queries with a single request. Note that you'll need to [normalize sparse and dense values](/guides/search/hybrid-search#normalize-sparse-and-dense-values) at query time so the unbounded sparse component doesn't dominate the combined score.
* [Use separate indexes for dense and sparse vectors](/guides/search/hybrid-search#use-separate-indexes-for-dense-and-sparse-vectors). This approach provides more flexibility but requires managing two indexes, maintaining linkages between vectors, and querying each index separately before merging results.
If you'd rather not tune sparse and dense weights at all, an [index with a document schema](/guides/get-started/concepts#document) with a multi-field schema is a simpler single-index alternative: declare FTS-enabled `string` fields alongside a `dense_vector` or `sparse_vector` field on the same index, then either restrict the dense (or sparse) search with a text-match filter on the lexical field, or run separate searches and merge the results client-side.
For more details, including guidance on choosing the right approach, see [Hybrid search](/guides/search/hybrid-search).
## Explore chunking strategies
You can chunk your content in different ways to get better results. Consider factors like the length of the content, the complexity of queries, and how results will be used in your application.
For more details, see [Chunking strategies](https://www.pinecone.io/learn/chunking-strategies/).
# Increase throughput
Source: https://docs.pinecone.io/guides/optimize/increase-throughput
Increase Pinecone throughput with bulk import from object storage, batch upserts, parallel requests, and the Python gRPC SDK for faster ingestion.
## Import from object storage
[Importing from object storage](/guides/index-data/import-data) is the most efficient and cost-effective method to load large numbers of records into an index. You store your data as Parquet files in object storage, integrate your object storage with Pinecone, and then start an asynchronous, long-running operation that imports and indexes your records.
## Upsert in batches
[Upserting in batches](/guides/index-data/upsert-data#upsert-in-batches) is another efficient way to ingest large numbers of records (up to 1000 per batch). Batch upserting is also a good option if you cannot work around bulk import's current [limitations](/guides/index-data/import-data#import-limits).
## Upsert/search in parallel
Pinecone is thread-safe, so you can send multiple [upsert](/guides/index-data/upsert-data#upsert-in-parallel) requests and multiple [query](/guides/search/semantic-search#parallel-queries) requests in parallel to help increase throughput.
## Python SDK options
### Use gRPC
Use the [Python SDK with gRPC extras](/reference/sdks/python/overview) to run data operations such as upserts and queries over [gRPC](https://grpc.io/) rather than HTTP for a modest performance improvement.
### Upsert from a dataframe
To quickly ingest data when using the Python SDK, use the [`upsert_from_dataframe` method](/reference/sdks/python/overview#upsert-from-a-dataframe). The method includes retry logic and `batch_size`, and is performant especially with Parquet file data sets.
## See also
Read more about [high-throughput optimizations](https://www.pinecone.io/blog/working-at-scale/) on our blog.
# Save on costs
Source: https://docs.pinecone.io/guides/optimize/save-on-costs
Save on Pinecone costs by using bulk import over upsert, namespaces for multitenancy, and query patterns that reduce read unit consumption.
## Credits and discounts
In addition to the workload optimizations below, you can lower your effective rate:
* **Prepaid credits and annual commitments** earn discounted usage rates. See [Prepaid credits](/guides/manage-cost/understanding-cost#prepaid-credits).
* **One-time bulk import credit.** Standard and Enterprise organizations receive a one-time 1 TB credit for [importing data from object storage](/guides/manage-cost/understanding-cost#imports).
* **Dedicated read nodes** can lower cost for sustained, high read throughput when you fully use the provisioned capacity (see [Choose the right index capacity mode](#choose-the-right-index-capacity-mode)).
* **Volume discounts.** Standard and Enterprise customers can [contact Support](https://app.pinecone.io/organizations/-/settings/support/ticket) to discuss cost optimization and discounts.
## Prefer bulk import over upsert for large loads
When you need to populate a new namespace or load a large dataset (for example, millions of records or hundreds of GB), [importing from object storage](/guides/index-data/import-data) is usually the most efficient and cost-effective path compared to streaming [upserts](/guides/index-data/upsert-data).
* **Import** is optimized for one-time or bulk loads from Parquet in your object store and is priced based on data read during the job. See [Import cost](/guides/manage-cost/understanding-cost#imports).
* **Upsert** is priced in write units based on request size; many small requests can cost more than fewer large ones for the same total data. See [Write unit pricing](/guides/manage-cost/understanding-cost#write-units).
Use upsert (including [batch upsert](/guides/index-data/upsert-data#upsert-in-batches)) for ongoing, incremental ingestion after your initial load. For how import and upsert compare, see the [data ingestion overview](/guides/index-data/data-ingestion-overview).
Partitioning tenants with [namespaces](/guides/index-data/implement-multitenancy) instead of many separate indexes often lowers storage overhead and query cost, because cost depends in part on how much data each query scans. For patterns and rationale, see [Manage cost](/guides/manage-cost/manage-cost#use-namespaces-for-multitenancy).
## Right-size reads and queries
* Avoid returning vector values in read responses when you do not need them (`include_values=false`), especially at high `top_k`. Values are typically the largest part of a response, so omitting them lowers [egress](/guides/manage-cost/understanding-cost#egress) and helps you stay within your plan's egress allowance.
* Use [metadata filters](/guides/search/filter-by-metadata) so queries scan fewer records where your workload allows.
Omitting values lowers egress, not [read units](/guides/manage-cost/understanding-cost#read-units): query read unit cost depends on the size of the namespace scanned, not on the size of the response.
Indexes built on [Dedicated Read Nodes](/guides/index-data/dedicated-read-nodes) are not subject to read unit limits for query, fetch, and list operations. For sizing and capacity planning guidance, see the [Dedicated Read Nodes](/guides/index-data/dedicated-read-nodes) guide.
## Choose the right index capacity mode
For sustained, high read throughput, [dedicated read nodes](/guides/index-data/dedicated-read-nodes) can be more cost-effective than on-demand when you fully utilize provisioned read capacity. For spiky or low-QPS workloads, on-demand may be cheaper. See [When to use dedicated read nodes](/guides/index-data/dedicated-read-nodes#when-to-use-dedicated-read-nodes) and [Understanding cost](/guides/manage-cost/understanding-cost).
## See also
* [Decrease latency](/guides/optimize/decrease-latency)
* [Increase throughput](/guides/optimize/increase-throughput)
* [Manage cost](/guides/manage-cost/manage-cost)
# Access your invoices
Source: https://docs.pinecone.io/guides/organizations/manage-billing/access-your-invoices
View and download your Pinecone organization billing invoices in the console, including invoice history, receipts, and payment records.
You can access your billing history and invoices in the Pinecone console:
1. Go to [**Settings > Billing > Overview**](https://app.pinecone.io/organizations/-/settings/billing).
2. Scroll down to the **Payment history and invoices** section.
3. For each billing period, you can download the invoice by clicking the **Download** button.
Each invoice includes line items for the services used during the billing period. If the total cost of that usage is below the monthly minimum, the invoice also includes a line item covering the rest of the minimum usage commitment.
# Change your payment method
Source: https://docs.pinecone.io/guides/organizations/manage-billing/change-payment-method
Update your Pinecone organization payment method in the console, including credit card details, billing address, and payment preferences.
You can pay for the [Standard and Enterprise plans](https://www.pinecone.io/pricing/) with a credit/debit card or through the AWS Marketplace, Microsoft Marketplace, or Google Cloud Marketplace. This page describes how to switch between these payment methods.
To change your payment method, you must be an [organization owner or billing admin](/guides/organizations/understanding-organizations#organization-roles).
The [Builder plan](https://www.pinecone.io/pricing/) is available with credit/debit card billing only and is not supported through cloud marketplaces.
To switch a Builder-plan organization to marketplace billing, first [upgrade to the Standard or Enterprise plan](/guides/organizations/manage-billing/upgrade-billing-plan) using the marketplace subscription flow.
## Credit card → marketplace
To change from credit card to marketplace billing, you'll need to:
1. Create a new Pinecone organization through the marketplace
2. Migrate your existing projects to the new Pinecone organization
3. Add your team members to the new Pinecone organization
4. Downgrade your original Pinecone organization once migration is complete
To change from paying with a credit card to paying through the Google Cloud Marketplace, do the following:
1. Subscribe to Pinecone in the Google Cloud Marketplace:
1. In the Google Cloud Marketplace, go to the [Pinecone listing](https://console.cloud.google.com/marketplace/product/pinecone-public/pinecone).
2. Click **Subscribe**.
3. On the **Order Summary** page, select a billing account, accept the terms and conditions, and click **Subscribe**.
The billing unit listed does not reflect the actual cost or metering of costs for Pinecone. See the [Pinecone Pricing page](https://www.pinecone.io/pricing/) for accurate details.
4. On the **Your order request has been sent to Pinecone** modal, click **Sign up with Pinecone**. This takes you to a Google-specific Pinecone sign-up page.
5. Sign up using the same authentication method as your existing Pinecone organization.
2. Create a new Pinecone organization and connect it to your Google Cloud Marketplace account:
1. On the **Connect GCP to Pinecone** page, choose **Select an organization > + Create New Organization**.
If you see a message saying that the subscription is still in process, wait a few minutes, refresh the page, and proceed only when the message has disappeared.
2. Enter the name of the new organization and click **Connect to Pinecone**.
3. On the **Confirm GCP marketplace Connection** modal, click **Connect**. This takes you to your new organization in the Pinecone console.
3. Migrate your projects to the new Pinecone organization:
1. In the Pinecone console, go to [**Settings > Access > Members**](https://app.pinecone.io/organizations/-/settings/access/members).
2. Make sure the **Owner** email address for your original organization is set as an **Owner** or **Billing Admin** for your new organization. This allows Pinecone to verify that both the original and new organizations are owned by the same person.
3. Go to [**Settings > Manage**](https://app.pinecone.io/organizations/-/settings/manage) and copy your new organization ID.
4. Go to [**Settings > Support > Tickets**](https://app.pinecone.io/organizations/-/settings/support/ticket/create).
5. For **Ticket category**, select **Project or Organization Management**.
6. For **Subject**, enter "Migrate projects to a new organization".
7. For **Description**, enter the following:
```
I am changing my payment method from credit card to Google Cloud Marketplace.
Please migrate my projects to my new organization: ``
```
8. Click **Submit**.
4. Add your team members to the new organization:
1. In the Pinecone console, go to [**Settings > Access > Members**](https://app.pinecone.io/organizations/-/settings/access/members).
2. [Add your team members to the new organization](/guides/organizations/manage-organization-members#add-a-member-to-an-organization).
5. Downgrade your original Pinecone organization:
Do not downgrade your original organization until you receive a confirmation that Pinecone has finished the migration to your new organization.
1. In the Pinecone console, go to your original organization.
2. Go to **Settings > Billing > Plans**.
3. In the **Starter** section, click **Downgrade**.
4. Click **Confirm downgrade**.
Going forward, your usage of Pinecone will be billed through the Google Cloud Marketplace.
You can [delete your original organization](/troubleshooting/delete-your-organization). However, before deleting, make sure to [download your past invoices](/guides/organizations/manage-billing/access-your-invoices) since you will lose access to them once the organization is deleted.
To change from paying with a credit card to paying through the AWS Marketplace, do the following:
1. Subscribe to Pinecone in the AWS Marketplace:
1. In the AWS Marketplace, go to the [Pinecone listing](https://aws.amazon.com/marketplace/pp/prodview-xhgyscinlz4jk).
2. Click **View purchase options**.
3. On the **Subscribe to Pinecone Vector Database** page, review the offer and then click **Subscribe**.
The billing unit listed does not reflect the actual cost or metering of costs for Pinecone. See the [Pinecone Pricing page](https://www.pinecone.io/pricing/) for accurate details.
4. You'll see a message stating that your subscription is in process. Click **Set up your account**. This takes you to an AWS-specific Pinecone sign-up page.
5. Sign up using the same authentication method as your existing Pinecone organization.
2. Create a new Pinecone organization and connect it to your AWS account:
1. On the **Connect AWS to Pinecone** page, choose **Select an organization > + Create New Organization**.
If you see a message saying that the subscription is still in process, wait a few minutes, refresh the page, and proceed only when the message has disappeared.
1. Enter the name of the new organization and click **Connect to Pinecone**.
2. On the **Confirm AWS Marketplace Connection** modal, click **Connect**. This takes you to your new organization in the Pinecone console.
3. Migrate your projects to the new Pinecone organization:
1. In the Pinecone console, go to [**Settings > Access > Members**](https://app.pinecone.io/organizations/-/settings/access/members).
2. Make sure the **Owner** email address for your original organization is set as an **Owner** or **Billing Admin** for your new organization. This allows Pinecone to verify that both the original and new organizations are owned by the same person.
3. Go to [**Settings > Manage**](https://app.pinecone.io/organizations/-/settings/manage) and copy your new organization ID.
4. Go to [**Settings > Support > Tickets**](https://app.pinecone.io/organizations/-/settings/support/ticket/create).
5. For **Ticket category**, select **Project or Organization Management**.
6. For **Subject**, enter "Migrate projects to a new organization".
7. For **Description**, enter the following:
```
I am changing my payment method from credit card to Google Cloud Marketplace.
Please migrate my projects to my new organization: ``
```
8. Click **Submit**.
4. Add your team members to the new organization:
1. In the Pinecone console, go to [**Settings > Access > Members**](https://app.pinecone.io/organizations/-/settings/access/members).
2. [Add your team members to the new organization](/guides/organizations/manage-organization-members#add-a-member-to-an-organization).
5. Downgrade your original Pinecone organization:
Do not downgrade your original organization until you receive a confirmation that Pinecone has finished the migration to your new organization.
1. In the Pinecone console, go to your original organization.
2. Go to **Settings > Billing > Plans**.
3. In the **Starter** section, click **Downgrade**.
4. Click **Confirm downgrade**.
Going forward, your usage of Pinecone will be billed through the AWS Marketplace.
You can [delete your original organization](/troubleshooting/delete-your-organization). However, before deleting, make sure to [download your past invoices](/guides/organizations/manage-billing/access-your-invoices) since you will lose access to them once the organization is deleted.
To change from paying with a credit card to paying through the Microsoft Marketplace, do the following:
1. Subscribe to Pinecone in the Microsoft Marketplace:
1. In the Microsoft Marketplace, go to the [Pinecone listing](https://marketplace.microsoft.com/product/saas/pineconesystemsinc1688761585469.pineconesaas).
2. Click **Get it now**.
3. Select the **Pinecone - Pay As You Go** plan.
4. Click **Subscribe**.
5. On the **Subscribe to Pinecone** page, select the required details and click **Review + subscribe**.
The billing unit listed does not reflect the actual cost or metering of costs for Pinecone. See the [Pinecone Pricing page](https://www.pinecone.io/pricing/) for accurate details.
6. Click **Subscribe**.
7. After the subscription is approved, click **Configure account now**. This redirects you to an Microsoft-specific Pinecone login page.
8. Sign up using the same authentication method as your existing Pinecone organization.
2. Create a new Pinecone organization and connect it to your Microsoft Marketplace account:
1. On the **Connect Azure to Pinecone** page, choose **Select an organization > + Create New Organization**.
If you see a message saying that the subscription is still in process, wait a few minutes, refresh the page, and proceed only when the message has disappeared.
1. Enter the name of the new organization and click **Connect to Pinecone**.
2. On the **Connect Azure marketplace connection** modal, click **Connect**. This takes you to your new organization in the Pinecone console.
3. Migrate your projects to the new Pinecone organization:
1. In the Pinecone console, go to [**Settings > Access > Members**](https://app.pinecone.io/organizations/-/settings/access/members).
2. Make sure the **Owner** email address for your original organization is set as an **Owner** or **Billing Admin** for your new organization. This allows Pinecone to verify that both the original and new organizations are owned by the same person.
3. Go to [**Settings > Manage**](https://app.pinecone.io/organizations/-/settings/manage) and copy your new organization ID.
4. Go to [**Settings > Support > Tickets**](https://app.pinecone.io/organizations/-/settings/support/ticket/create).
5. For **Ticket category**, select **Project or Organization Management**.
6. For **Subject**, enter "Migrate projects to a new organization".
7. For **Description**, enter the following:
```
I am changing my payment method from credit card to Microsoft Marketplace.
Please migrate my projects to my new organization: ``
```
8. Click **Submit**.
4. Add your team members to the new organization:
1. In the Pinecone console, go to [**Settings > Access > Members**](https://app.pinecone.io/organizations/-/settings/access/members).
2. [Add your team members to the new organization](/guides/organizations/manage-organization-members#add-a-member-to-an-organization).
5. Downgrade your original Pinecone organization:
Do not downgrade your original organization until you receive a confirmation that Pinecone has finished the migration to your new organization.
1. In the Pinecone console, go to your original organization.
2. Go to **Settings > Billing > Plans**.
3. In the **Starter** section, click **Downgrade**.
4. Click **Confirm downgrade**.
Going forward, your usage of Pinecone will be billed through the Microsoft Marketplace.
You can [delete your original organization](/troubleshooting/delete-your-organization). However, before deleting, make sure to [download your past invoices](/guides/organizations/manage-billing/access-your-invoices) since you will lose access to them once the organization is deleted.
## Marketplace → credit card
To change from marketplace billing to credit card, you'll need to:
1. Create a new organization in your Pinecone account
2. Upgrade the new organization to the Standard or Enterprise plan
3. Migrate your existing projects to the new organization
4. Add your team members to the new organization
5. Downgrade your original organization once migration is complete
To change from paying through the Google Cloud Marketplace to paying with a credit card, do the following:
1. Create a new organization in your Pinecone account:
1. In the Pinecone console, go to [**Organizations**](https://app.pinecone.io/organizations/-/settings/account/organizations).
2. Click **+ Create organization**.
3. Enter the name of the new organization and click **Create**.
2. Upgrade the new organization:
1. Go to [Settings > Billing > Plans](https://app.pinecone.io/organizations/-/settings/billing/plans).
2. Click **Upgrade** in the **Standard** or **Enterprise** plan section.
3. Click **Credit / Debit card**.
4. Enter your credit card information.
5. Click **Upgrade**.
The new organization is now set up with credit card billing. You'll use this organization after completing the rest of this process.
3. Migrate your projects to the new Pinecone organization:
1. Go to [**Settings > Manage**](https://app.pinecone.io/organizations/-/settings/manage) and copy your new organization ID.
2. Go to [**Settings > Support > Tickets**](https://app.pinecone.io/organizations/-/settings/support/ticket/create).
3. For **Ticket category**, select **Project or Organization Management**.
4. For **Subject**, enter "Migrate projects to a new organization".
5. For **Description**, enter the following:
```
I am changing my payment method from Google Cloud Marketplace to credit card.
Please migrate my projects to my new organization: ``
```
6. Click **Submit**.
4. Add your team members to the new organization:
1. In the Pinecone console, go to [**Settings > Access > Members**](https://app.pinecone.io/organizations/-/settings/access/members).
2. [Add your team members to the new organization](/guides/organizations/manage-organization-members#add-a-member-to-an-organization).
5. Downgrade your original Pinecone organization:
Do not downgrade your original organization until you receive a confirmation that Pinecone has finished the migration to your new organization.
1. In the Pinecone console, go to your original organization.
2. Go to [**Settings > Billing > Plans**](https://app.pinecone.io/organizations/-/settings/billing/plans).
3. In the **Starter** section, click **Downgrade**.
4. Click **Confirm downgrade**.
5. On the **Continue your downgrade on the GCP marketplace** modal, click **Continue to marketplace**. This takes you to your orders page in Google Cloud Marketplace.
6. [Cancel the order](https://cloud.google.com/marketplace/docs/manage-billing#saas-products) for your original organization.
If you don't see the order, check that the correct billing account is selected.
Going forward, you'll use your new organization and your usage will be billed through the credit card you provided.
You can [delete your original organization](/troubleshooting/delete-your-organization). However, before deleting, make sure to [download your past invoices](/guides/organizations/manage-billing/access-your-invoices) since you will lose access to them once the organization is deleted.
To change from paying through the AWS Marketplace to paying with a credit card, do the following:
1. Create a new organization in your Pinecone account:
1. In the Pinecone console, go to [**Organizations**](https://app.pinecone.io/organizations/-/settings/account/organizations).
2. Click **+ Create organization**.
3. Enter the name of the new organization and click **Create**.
2. Upgrade the new organization:
1. Go to [Settings > Billing > Plans](https://app.pinecone.io/organizations/-/settings/billing/plans).
2. Click **Upgrade** in the **Standard** or **Enterprise** plan section.
3. Click **Credit / Debit card**.
4. Enter your credit card information.
5. Click **Upgrade**.
The new organization is now set up with credit card billing. You'll use this organization after completing the rest of this process.
3. Migrate your projects to the new Pinecone organization:
1. Go to [**Settings > Manage**](https://app.pinecone.io/organizations/-/settings/manage) and copy your new organization ID.
2. Go to [**Settings > Support > Tickets**](https://app.pinecone.io/organizations/-/settings/support/ticket/create).
3. For **Ticket category**, select **Project or Organization Management**.
4. For **Subject**, enter "Migrate projects to a new organization".
5. For **Description**, enter the following:
```
I am changing my payment method from AWS Marketplace to credit card.
Please migrate my projects to my new organization: ``
```
6. Click **Submit**.
4. Add your team members to the new organization:
1. In the Pinecone console, go to [**Settings > Access > Members**](https://app.pinecone.io/organizations/-/settings/access/members).
2. [Add your team members to the new organization](/guides/organizations/manage-organization-members#add-a-member-to-an-organization).
5. Downgrade your original Pinecone organization:
Do not downgrade your original organization until you receive a confirmation that Pinecone has finished the migration to your new organization.
1. In the Pinecone console, go to your original organization.
2. Go to [**Settings > Billing > Plans**](https://app.pinecone.io/organizations/-/settings/billing/plans).
3. In the **Starter** section, click **Downgrade**.
4. Click **Confirm downgrade**.
5. On the **Continue your downgrade on the AWS marketplace** modal, click **Continue to marketplace**. This takes you to the [Manage subscriptions](https://console.aws.amazon.com/marketplace) page in the AWS Marketplace.
6. [Cancel the subscription](https://docs.aws.amazon.com/marketplace/latest/buyerguide/cancel-subscription.html#cancel-saas-subscription) to Pinecone.
Going forward, you'll use your new organization and your usage will be billed through the credit card you provided.
You can [delete your original organization](/troubleshooting/delete-your-organization). However, before deleting, make sure to [download your past invoices](/guides/organizations/manage-billing/access-your-invoices) since you will lose access to them once the organization is deleted.
To change from paying through the Microsoft Marketplace to paying with a credit card, do the following:
1. Create a new organization in your Pinecone account:
1. In the Pinecone console, go to [**Organizations**](https://app.pinecone.io/organizations/-/settings/account/organizations).
2. Click **+ Create organization**.
3. Enter the name of the new organization and click **Create**.
2. Upgrade the new organization:
1. Go to [Settings > Billing > Plans](https://app.pinecone.io/organizations/-/settings/billing/plans).
2. Click **Upgrade** in the **Standard** or **Enterprise** plan section.
3. Click **Credit / Debit card**.
4. Enter your credit card information.
5. Click **Upgrade**.
The new organization is now set up with credit card billing. You'll use this organization after completing the rest of this process.
3. Migrate your projects to the new Pinecone organization:
1. Go to [**Settings > Manage**](https://app.pinecone.io/organizations/-/settings/manage) and copy your new organization ID.
2. Go to [**Settings > Support > Tickets**](https://app.pinecone.io/organizations/-/settings/support/ticket/create).
3. For **Ticket category**, select **Project or Organization Management**.
4. For **Subject**, enter "Migrate projects to a new organization".
5. For **Description**, enter the following:
```
I am changing my payment method from Microsoft Marketplace to credit card.
Please migrate my projects to my new organization: ``
```
6. Click **Submit**.
4. Add your team members to the new organization:
1. In the Pinecone console, go to [**Settings > Access > Members**](https://app.pinecone.io/organizations/-/settings/access/members).
2. [Add your team members to the new organization](/guides/organizations/manage-organization-members#add-a-member-to-an-organization).
5. Downgrade your original Pinecone organization:
Do not downgrade your original organization until you receive a confirmation that Pinecone has finished the migration to your new organization.
1. In the Pinecone console, go to your original organization.
2. Go to [**Settings > Billing > Plans**](https://app.pinecone.io/organizations/-/settings/billing/plans).
3. In the **Starter** section, click **Downgrade**.
4. Click **Confirm downgrade**.
5. On the **Continue your downgrade on Azure marketplace** modal, click **Continue to marketplace**.
6. On the **SaaS** page, click your subscription to Pinecone.
7. Click **Cancel subscription**.
8. Confirm the cancellation.
Going forward, you'll use your new organization and your usage will be billed through the credit card you provided.
You can [delete your original organization](/troubleshooting/delete-your-organization). However, before deleting, make sure to [download your past invoices](/guides/organizations/manage-billing/access-your-invoices) since you will lose access to them once the organization is deleted.
## Marketplace → marketplace
To change from one marketplace to another, you'll need to:
1. Subscribe to Pinecone in the new marketplace
2. Connect your existing org to the new marketplace
3. Cancel your subscription in the old marketplace
To change to a Google Cloud Marketplace billing account, do the following:
1. Subscribe to Pinecone in the Google Cloud Marketplace:
1. In the Google Cloud Marketplace, go to the [Pinecone listing](https://console.cloud.google.com/marketplace/product/pinecone-public/pinecone).
2. Click **Subscribe**.
3. On the **Order Summary** page, select a billing account, accept the terms and conditions, and click **Subscribe**.
The billing unit listed does not reflect the actual cost or metering of costs for Pinecone. See the [Pinecone Pricing page](https://www.pinecone.io/pricing/) for accurate details.
4. On the **Your order request has been sent to Pinecone** modal, click **Sign up with Pinecone**. This takes you to a Google-specific Pinecone login page.
5. Log in to your Pinecone account. Use the same authentication method as your existing Pinecone organization.
2. Connect your existing org to your Google account:
1. On the **Connect GCP to Pinecone** page, select the Pinecone organization that you want to use Google Cloud Marketplace.
If you see a message saying that the subscription is still in process, wait a few minutes, refresh the page, and proceed only when the message has disappeared.
2. On the **Confirm GCP marketplace connection** modal, click **Connect**. This takes you to your organization in the Pinecone console.
Going forward, your usage of Pinecone will be billed through the Google Cloud Marketplace.
3. Cancel your subscription in your previous marketplace:
* For AWS:
1. In the AWS Marketplace, go to the [Manage subscriptions](https://console.aws.amazon.com/marketplace) page in the AWS Marketplace.
2. [Cancel the subscription](https://docs.aws.amazon.com/marketplace/latest/buyerguide/cancel-subscription.html#cancel-saas-subscription) to Pinecone.
* For Microsoft:
1. Go to [Azure SaaS Resource Management](https://portal.azure.com/#blade/HubsExtension/BrowseResourceBlade/resourceType/Microsoft.SaaS%2Fresources).
2. Select your subscription to Pinecone.
3. Click **Cancel subscription**.
4. Confirm the cancellation.
To change to an AWS Marketplace billing account, do the following:
1. Subscribe to Pinecone in the AWS Marketplace:
1. In the AWS Marketplace, go to the [Pinecone listing](https://aws.amazon.com/marketplace/pp/prodview-xhgyscinlz4jk) in the AWS Marketplace.
2. Click **View purchase options**.
3. On the **Subscribe to Pinecone Vector Database** page, review the offer and then click **Subscribe**.
The billing unit listed does not reflect the actual cost or metering of costs for Pinecone. See the [Pinecone Pricing page](https://www.pinecone.io/pricing/) for accurate details.
4. You'll see a message stating that your subscription is in process. Click **Set up your account**. This takes you to an AWS-specific Pinecone login page.
5. Log in to your Pinecone account. Use the same authentication method as your existing Pinecone organization.
2. Connect your existing org to your AWS account:
1. On the **Connect AWS to Pinecone** page, select the Pinecone organization that you want to change to AWS Marketplace.
If you see a message saying that the subscription is still in process, wait a few minutes, refresh the page, and proceed only when the message has disappeared.
2. On the **Confirm AWS marketplace connection** modal, click **Connect**. This takes you to your organization in the Pinecone console.
Going forward, your usage of Pinecone will be billed through the AWS Marketplace.
3. Cancel your subscription in your previous marketplace:
* For Google Cloud Marketplace:
1. Go to the [Orders](https://console.cloud.google.com/marketplace/orders) page.
2. [Cancel the order](https://cloud.google.com/marketplace/docs/manage-billing#saas-products) for Pinecone.
* For Microsoft Marketplace:
1. Go to [Azure SaaS Resource Management](https://portal.azure.com/#blade/HubsExtension/BrowseResourceBlade/resourceType/Microsoft.SaaS%2Fresources).
2. Select your subscription to Pinecone.
3. Click **Cancel subscription**.
4. Confirm the cancellation.
To change to a Microsoft Marketplace billing account, do the following:
1. Subscribe to Pinecone in the Microsoft Marketplace:
1. In the Microsoft Marketplace, go to the [Pinecone listing](https://marketplace.microsoft.com/product/saas/pineconesystemsinc1688761585469.pineconesaas).
2. Click **Get it now**.
3. Select the **Pinecone - Pay As You Go** plan.
4. Click **Subscribe**.
5. On the **Subscribe to Pinecone** page, select the required details and click **Review + subscribe**.
The billing unit listed does not reflect the actual cost or metering of costs for Pinecone. See the [Pinecone Pricing page](https://www.pinecone.io/pricing/) for accurate details.
6. Click **Subscribe**.
7. After the subscription is approved, click **Configure account now**. This redirects you to an Microsoft-specific Pinecone login page.
8. Log in to your Pinecone account. Use the same authentication method as your existing Pinecone organization.
2. Connect your existing org to your Microsoft account:
1. On the **Connect Azure to Pinecone** page, select the Pinecone organization that you want to change to Microsoft Marketplace.
If you see a message saying that the subscription is still in process, wait a few minutes, refresh the page, and proceed only when the message has disappeared.
2. On the **Confirm Azure marketplace connection** modal, click **Connect**. This takes you to your organization in the Pinecone console.
Going forward, your usage of Pinecone will be billed through the Microsoft Marketplace.
3. Cancel your subscription in your previous marketplace:
* For Google Cloud Marketplace:
1. Go to the [Orders](https://console.cloud.google.com/marketplace/orders) page.
2. [Cancel the order](https://cloud.google.com/marketplace/docs/manage-billing#saas-products) for Pinecone.
* For AWS Marketplace:
1. Go to the [Manage subscriptions](https://console.aws.amazon.com/marketplace) page in the AWS Marketplace.
2. [Cancel the subscription](https://docs.aws.amazon.com/marketplace/latest/buyerguide/cancel-subscription.html#cancel-saas-subscription) to Pinecone.
## Credit card → credit card
To update your credit card information in the Pinecone console, do the following:
1. Go to [**Settings > Billing > Overview**](https://app.pinecone.io/organizations/-/settings/billing).
2. In the **Billing Contact** section, click **Edit**.
3. Enter your new credit card information.
4. Click **Update**.
# Downgrade your plan
Source: https://docs.pinecone.io/guides/organizations/manage-billing/downgrade-billing-plan
Downgrade your Pinecone organization from a paid plan to the free Starter plan, including plan requirements, index limits, and billing impact.
To change your billing plan, you must be an [organization owner or billing admin](/guides/organizations/understanding-organizations#organization-roles).
If you are on the Standard plan with credit/debit card billing and want to reduce spend without returning to the free Starter plan, consider [switching to the Builder plan](#switch-from-standard-to-builder) for a flat \$20/month.
## Requirements
Before you can downgrade, your organization must be under the [Starter plan quotas](/reference/api/database-limits):
* No more than 5 indexes, all serverless and in the `us-east-1` region of AWS
* If you have serverless indexes in a region other than `us-east-1`, [create a new serverless index](/guides/index-data/create-an-index#create-a-serverless-index) in `us-east-1`, [re-upsert your data](/guides/index-data/upsert-data) into the new index, and [delete the old index](/guides/manage-data/manage-indexes#delete-an-index).
* If you have more than 5 serverless indexes, [delete indexes](/guides/manage-data/manage-indexes#delete-an-index) until you have 5 or fewer.
* If you have pod-based indexes, [delete them](/guides/manage-data/manage-indexes#delete-an-index).
* No more than 1 project
* If you have more than 1 project, [delete all but 1 project](/guides/projects/manage-projects#delete-a-project).
* Before you can delete a project, you must [delete all indexes](/guides/manage-data/manage-indexes#delete-an-index) and [delete all collections](/guides/manage-data/back-up-an-index#delete-a-collection) in the project.
* No more than 2 GB of data across all of your serverless indexes
* If you are storing more than 2 GB of data, [delete records](/guides/manage-data/delete-data) until you're storing less than 2 GB.
* No more than 100 namespaces per serverless index
* If any serverless index has more than 100 namespaces, [delete namespaces](/guides/manage-data/delete-data#delete-all-records-from-a-namespace) until it has 100 or fewer remaining.
* No more than 3 [assistants](/guides/assistant/overview)
* If you have more than 3 assistants, [delete assistants](/guides/assistant/manage-assistants#delete-an-assistant) until you have 3 or fewer.
* Within the Starter plan's monthly [ingestion](/guides/assistant/pricing-and-limits#ingestion) and token limits
* Your usage must fit within the Starter plan limits for [ingestion units](/guides/assistant/pricing-and-limits#ingestion), chat tokens, context tokens, and storage. Reduce files or usage until you are within those limits.
* No more than 1 GB of assistant storage
* If you have more than 1 GB of assistant storage, [delete files](https://docs.pinecone.io/guides/assistant/manage-files#delete-a-file) until you're storing less than 1 GB.
* No more than 2 users
* No collections or backups (these are automatically deleted as part of the downgrade process)
You do not need to bring [Assistant usage](/guides/assistant/pricing-and-limits) (ingestion, tokens, and so on) under Starter caps before downgrading. If you exceed Starter limits after downgrading, new requests may be blocked until usage is within limits.
**Switching from Standard to Builder instead of Starter?** Your organization must be under the [Builder plan quotas](/reference/api/database-limits), backups must be deleted, and any features not available on Builder—such as bulk import, pod-based indexes, storage integrations, RBAC, and SSO—must be removed or stopped.
## Downgrade to the Starter plan
The downgrade process is different depending on how you are paying for Pinecone.
It is important to start the downgrade process in the Pinecone console, as described below. When you do so, Pinecone checks that you are under the [Starter plan quotas](#requirements) before allowing you to downgrade. In contrast, if you start the downgrade process in one of the cloud marketplaces, Pinecone cannot check that you are under these quotas before allowing you to downgrade. If you are over the quotas, Pinecone will deactivate your account, and you will need to [contact support](https://www.pinecone.io/contact/support/).
If you are paying with a credit card, downgrade as follows:
1. In the Pinecone console, go to [**Settings > Billing > Plans**](https://app.pinecone.io/organizations/-/settings/billing/plans).
2. Click **Downgrade** in the **Starter** plan section.
Your billing will end immediately. However, you will receive a final invoice for any charges accrued in the current month.
If you are paying through the Google Cloud Marketplace, downgrade as follows:
1. In the Pinecone console, go to [**Settings > Billing > Plans**](https://app.pinecone.io/organizations/-/settings/billing/plans).
2. In the **Starter** section, click **Downgrade**.
3. Click **Confirm downgrade**.
4. On the **Continue your downgrade on the GCP marketplace** modal, click **Continue to marketplace**. This takes you to your orders page in Google Cloud Marketplace.
5. [Cancel the order](https://cloud.google.com/marketplace/docs/manage-billing#saas-products) for your Pinecone subscription.
If you don't see the order, check that the correct billing account is selected.
Your billing will end immediately. However, you will receive a final invoice for any charges accrued in the current month.
If you are paying through the AWS Marketplace, downgrade as follows:
1. In the Pinecone console, go to [**Settings > Billing > Plans**](https://app.pinecone.io/organizations/-/settings/billing/plans).
2. In the **Starter** section, click **Downgrade**.
3. Click **Confirm downgrade**.
4. On the **Continue your downgrade on the AWS marketplace** modal, click **Continue to marketplace**. This takes you to the [Manage subscriptions](https://console.aws.amazon.com/marketplace) page in the AWS Marketplace.
5. [Cancel the subscription](https://docs.aws.amazon.com/marketplace/latest/buyerguide/cancel-subscription.html#cancel-saas-subscription) to Pinecone.
Your billing will end immediately. However, you will receive a final invoice for any charges accrued in the current month.
If you are paying through the Microsoft Marketplace, downgrade as follows:
1. In the Pinecone console, go to [**Settings > Billing > Plans**](https://app.pinecone.io/organizations/-/settings/billing/plans).
2. In the **Starter** section, click **Downgrade**.
3. Click **Confirm downgrade**.
4. On the **Continue your downgrade on Microsoft marketplace** modal, click **Continue to marketplace**.
5. On the **SaaS** page, click your subscription to Pinecone.
6. Click **Cancel subscription**.
7. Confirm the cancellation.
Your billing will end immediately. However, you will receive a final invoice for any charges accrued in the current month.
## Switch from Standard to Builder
If you are on the **Standard plan** with credit/debit card billing and would like to switch to the [Builder plan](/reference/api/database-limits) (flat \$20/month), do the following:
1. Bring your organization under the [Builder plan quotas](/reference/api/database-limits). In particular, you must be within the Builder plan limits for projects, indexes, namespaces, storage, users, and monthly usage units.
2. In the Pinecone console, go to [**Settings > Billing > Plans**](https://app.pinecone.io/organizations/-/settings/billing/plans).
3. Click **Switch to Builder** in the **Builder** plan section.
4. Confirm the change.
After switching, overages are no longer billed—requests that exceed Builder quotas are blocked instead. If you need more capacity, [upgrade back to Standard or Enterprise](/guides/organizations/manage-billing/upgrade-billing-plan) at any time.
The [Builder plan](https://www.pinecone.io/pricing/) is available with credit/debit card billing only and is not supported through cloud marketplaces.
If you pay through a cloud marketplace, you cannot switch to the Builder plan at this time. [Contact Support](https://app.pinecone.io/organizations/-/settings/support/ticket) to be notified when this migration becomes available.
# Download a usage report
Source: https://docs.pinecone.io/guides/organizations/manage-billing/download-usage-report
Download detailed Pinecone usage and cost reports from the console, including index consumption, storage metrics, and per-project spend breakdowns.
To view usage and costs across your Pinecone organization, you must be an [organization owner or billing admin](/guides/organizations/understanding-organizations#organization-roles). Also, this feature is available only to organizations on the Standard or Enterprise plans.
The **Usage** dashboard in the Pinecone console gives you a detailed report of usage and costs across your organization, broken down by each billable SKU or aggregated by project or service. You can view the report in the console or download it as a CSV file for more detailed analysis.
1. Go to [**Settings > Usage**](https://app.pinecone.io/organizations/-/settings/usage) in the Pinecone console.
2. Select the time range to report on. This defaults to the last 30 days.
3. Select the scope for your report:
* **SKU:** The usage and cost for each billable SKU, for example, read units per cloud region, storage size per cloud region, or tokens per embedding model.
* **Project:** The aggregated cost for each project in your organization.
* **Service:** The aggregated cost for each service your organization uses, for example, database (includes serverless back up and restore), assistants, inference (embedding and reranking), and collections.
4. Choose the specific SKUs, projects, or services you want to report on. This defaults to all.
5. To download the report as a CSV file, click **Download**.
The CSV download provides more granular detail than the console view, including breakdowns by individual index as well as project and index tags.
Dates are shown in UTC to match billing invoices. Cost data is delayed up to three days from the actual usage date.
# Account deactivation for non-payment
Source: https://docs.pinecone.io/guides/organizations/manage-billing/non-payment-account-deactivation
Learn what happens when a Pinecone account is deactivated for non-payment: 30-day data retention, permanent deletion, and how to reactivate.
If your organization has continued non-payment on a paid billing plan, Pinecone may deactivate your account. While your account is deactivated, you cannot use Pinecone services, but your data is retained for a limited time so you can reactivate and recover it.
## Data retention after deactivation
When your account is deactivated for non-payment:
* Your account data is retained for **30 days** from deactivation.
* After 30 days, all account data is **permanently deleted**. This action cannot be undone.
This 30-day retention period applies specifically to accounts deactivated for continued non-payment. Other deletion flows, such as when you [delete resources](/guides/production/data-deletion) or [end your relationship with Pinecone](/guides/production/data-deletion), follow different retention timelines described in the [data deletion policy](/guides/production/data-deletion).
If you see a deactivation notice in the Pinecone console, it reflects this policy:
> Your account has been deactivated due to continued non-payment. Account data will be retained for 30 days. After 30 days, all data will be permanently deleted. This action cannot be undone.
>
> To reactivate your account and preserve your data, please visit the billing page and update your payment information. If you believe this is an error, please reach out to our support team.
## Reactivate your account
To reactivate your account and preserve your data before the 30-day retention period ends:
1. Sign in to the [Pinecone console](https://app.pinecone.io).
2. Go to [**Settings > Billing**](https://app.pinecone.io/organizations/-/settings/billing).
3. Update your payment information or resolve the outstanding balance.
Organization [owners and billing admins](/guides/organizations/understanding-organizations#organization-roles) can update billing details. For help changing how you pay, see [Change your payment method](/guides/organizations/manage-billing/change-payment-method).
## API access while deactivated
API requests may fail with a [**402 - Payment Required**](/reference/api/errors#402---payment-required) response while your account has a payment issue or is deactivated for non-payment. After you reactivate your account, retry your requests. For general error-handling guidance, see [Error handling](/guides/production/error-handling).
## Contact support
If you believe your account was deactivated in error, [contact Support](https://www.pinecone.io/contact/support/) or [open a support ticket](https://app.pinecone.io/organizations/-/settings/support/ticket) from the console.
## See also
* [Change your payment method](/guides/organizations/manage-billing/change-payment-method)
* [Data deletion on Pinecone](/guides/production/data-deletion)
* [Billing disputes and refunds](/troubleshooting/billing-disputes-and-refunds)
# Standard trial
Source: https://docs.pinecone.io/guides/organizations/manage-billing/standard-trial
Get $300 in credits over 21 days with the Pinecone Standard plan trial, including RBAC, bulk import, backup and restore, and higher scale limits.
The Standard trial lets you evaluate Pinecone without requiring any up-front payment. You get \$300 in credits over 21 days with access to Standard plan [features](https://www.pinecone.io/pricing/) and [limits](/reference/api/database-limits) that are suitable for testing Pinecone at scale.
If you're building a small or personal project, consider the free [Starter plan](https://www.pinecone.io/pricing/) or the flat-rate [Builder plan](https://www.pinecone.io/pricing/) instead.
## Key features
* \$300 in credits
* 21 days of access to Standard plan [features](https://www.pinecone.io/pricing/), including:
* [Bulk import](/guides/index-data/import-data)
* [Backup and restore](/guides/manage-data/backups-overview)
* [RBAC (role-based access control)](/guides/production/security-overview#role-based-access-controls-rbac)
* [Higher limits](/reference/api/database-limits) for testing at scale
* Access to all [cloud regions](/guides/index-data/create-an-index#cloud-regions)
* Access to [Developer Support](https://www.pinecone.io/pricing/?plans=support)
## Expiration
At the end of a Standard trial, or when you've used all of your credits, you can take one of the following actions:
* Add a payment method and continue on with the Standard plan.
* Upgrade to the Enterprise plan.
* [Downgrade to the Starter plan](#downgrading-to-the-starter-plan) (you can also do this before your trial expires, if you choose).
Learn more about [pricing](https://www.pinecone.io/pricing/).
## Downgrading to the Starter plan
To downgrade from a Standard trial to the Starter plan, you'll need to bring your usage within Starter plan limits.
* No more than 5 indexes, all serverless and in the `us-east-1` region of AWS
* If you have serverless indexes in a region other than `us-east-1`, [create a new serverless index](/guides/index-data/create-an-index#create-a-serverless-index) in `us-east-1`, [re-upsert your data](/guides/index-data/upsert-data) into the new index, and [delete the old index](/guides/manage-data/manage-indexes#delete-an-index).
* If you have more than 5 serverless indexes, [delete indexes](/guides/manage-data/manage-indexes#delete-an-index) until you have 5 or fewer.
* If you have pod-based indexes, [delete them](/guides/manage-data/manage-indexes#delete-an-index).
* No more than 1 project
* If you have more than 1 project, [delete all but 1 project](/guides/projects/manage-projects#delete-a-project).
* Before you can delete a project, you must [delete all indexes](/guides/manage-data/manage-indexes#delete-an-index) and [delete all collections](/guides/manage-data/back-up-an-index#delete-a-collection) in the project.
* No more than 2 GB of data across all of your serverless indexes
* If you are storing more than 2 GB of data, [delete records](/guides/manage-data/delete-data) until you're storing less than 2 GB.
* No more than 100 namespaces per serverless index
* If any serverless index has more than 100 namespaces, [delete namespaces](/guides/manage-data/delete-data#delete-all-records-from-a-namespace) until it has 100 or fewer remaining.
* No more than 3 [assistants](/guides/assistant/overview)
* If you have more than 3 assistants, [delete assistants](/guides/assistant/manage-assistants#delete-an-assistant) until you have 3 or fewer.
* Within the Starter plan's monthly [ingestion](/guides/assistant/pricing-and-limits#ingestion) and token limits
* Your usage must fit within the Starter plan limits for [ingestion units](/guides/assistant/pricing-and-limits#ingestion), chat tokens, context tokens, and storage. Reduce files or usage until you are within those limits.
* No more than 1 GB of assistant storage
* If you have more than 1 GB of assistant storage, [delete files](https://docs.pinecone.io/guides/assistant/manage-files#delete-a-file) until you're storing less than 1 GB.
* No more than 2 users
* No collections or backups (these are automatically deleted as part of the downgrade process)
You do not need to bring [Assistant usage](/guides/assistant/pricing-and-limits) (ingestion, tokens, and so on) under Starter caps before downgrading. If you exceed Starter limits after downgrading, new requests may be blocked until usage is within limits.
**Switching from Standard to Builder instead of Starter?** Your organization must be under the [Builder plan quotas](/reference/api/database-limits), backups must be deleted, and any features not available on Builder—such as bulk import, pod-based indexes, storage integrations, RBAC, and SSO—must be removed or stopped.
If you have questions, [contact Support](https://www.pinecone.io/contact/support/).
## Limits
* Each organization is allowed only one trial.
* Organizations already on a Builder, Standard, or Enterprise plan cannot activate a Standard plan trial.
* Organizations that initially subscribed to Pinecone through marketplace partners cannot activate a Standard plan trial.
If you have any questions, [contact Support](https://www.pinecone.io/contact/support/).
# Upgrade your plan
Source: https://docs.pinecone.io/guides/organizations/manage-billing/upgrade-billing-plan
Upgrade to a paid Pinecone plan for higher limits, backups, private endpoints, audit logs, and access to the Builder, Standard, or Enterprise tiers.
This page describes how to upgrade from the free Starter plan to the [Builder, Standard, or Enterprise plan](https://www.pinecone.io/pricing/), paying either with a credit/debit card or through a supported cloud marketplace.
To change your plan, you must be an [organization owner or billing admin](/guides/organizations/understanding-organizations#organization-roles).
To commit to annual spending, [contact Pinecone](https://www.pinecone.io/contact).
## Upgrade to the Builder plan
The Builder plan is a flat \$20/month plan with higher quotas than Starter and no usage overages. To upgrade from Starter to Builder:
1. In the Pinecone console, go to [Settings > Billing > Plans](https://app.pinecone.io/organizations/-/settings/billing/plans).
2. Click **Upgrade** in the **Builder** plan section.
3. Enter your credit/debit card information.
4. Click **Upgrade**.
After upgrading, your organization is immediately on the Builder plan with the higher [Builder plan quotas](/reference/api/database-limits). If you need additional capacity or features not included in Builder, you can [upgrade to Standard or Enterprise](#upgrade-to-the-standard-or-enterprise-plan) at any time.
The [Builder plan](https://www.pinecone.io/pricing/) is available with credit/debit card billing only and is not supported through cloud marketplaces.
## Upgrade to the Standard or Enterprise plan
### Pay with a credit/debit card
To upgrade your plan to Standard or Enterprise and pay with a credit/debit card, do the following:
1. In the Pinecone console, go to [Settings > Billing > Plans](https://app.pinecone.io/organizations/-/settings/billing/plans).
2. Click **Upgrade** in the **Standard** or **Enterprise** plan section.
3. Click **Credit / Debit card**.
4. Enter your credit card information.
5. Click **Upgrade**.
After upgrading, you will immediately start paying for usage of your Pinecone indexes, including the serverless indexes that were free on the Starter plan. For more details about how costs are calculated, see [Understanding cost](/guides/manage-cost/understanding-cost).
### Pay through the Google Cloud Marketplace
To upgrade your plan to Standard or Enterprise and pay through the Google Cloud Marketplace, do the following:
1. In the Pinecone console, go to [Settings > Billing > Plans](https://app.pinecone.io/organizations/-/settings/billing/plans).
2. Click **Upgrade** in the **Standard** or **Enterprise** plan section.
3. Click **Billing through GCP**. This takes you to the [Pinecone listing](https://console.cloud.google.com/marketplace/product/pinecone-public/pinecone) in the Google Cloud Marketplace.
4. Click **Subscribe**.
5. On the **Order Summary** page, select a billing account, accept the terms and conditions, and click **Subscribe**.
The billing unit listed does not reflect the actual cost or metering of costs for Pinecone. See the [Pinecone Pricing page](https://www.pinecone.io/pricing/) for accurate details.
6. On the **Your order request has been sent to Pinecone** modal, click **Sign up with Pinecone**. This takes you to a Google-specific Pinecone login page.
7. Log in to your Pinecone account. Use the same authentication method as your existing Pinecone organization.
8. Select an organization from the list. You can only connect to organizations that are on the [Starter plan](https://www.pinecone.io/pricing/). Alternatively, you can opt to create a new organization.
9. Click **Connect to Pinecone** and follow the prompts.
Once your organization is connected and upgraded, you will receive a confirmation message. You will then immediately start paying for usage of your Pinecone indexes, including the serverless indexes that were free on the Starter plan. For more details about how costs are calculated, see [Understanding cost](/guides/manage-cost/understanding-cost).
### Pay through the AWS Marketplace
To upgrade your plan to Standard or Enterprise and pay through the AWS Marketplace, do the following:
1. In the Pinecone console, go to [Settings > Billing > Plans](https://app.pinecone.io/organizations/-/settings/billing/plans).
2. Click **Upgrade** in the **Standard** or **Enterprise** plan section.
3. Click **Billing through AWS**. This takes you to the [Pinecone listing](https://aws.amazon.com/marketplace/pp/prodview-xhgyscinlz4jk) in the AWS Marketplace.
4. Click **View purchase options**.
5. On the **Subscribe to Pinecone Vector Database** page, review the offer and then click **Subscribe**.
The billing unit listed does not reflect the actual cost or metering of costs for Pinecone. See the [Pinecone Pricing page](https://www.pinecone.io/pricing/) for accurate details.
6. You'll see a message stating that your subscription is in process. Click **Set up your account**. This takes you to an AWS-specific Pinecone login page.
If the [Pinecone subscription page](https://aws.amazon.com/marketplace/saas/ordering?productId=738798c3-eeca-494a-a2a9-161bee9450b2) shows a message stating, “You are currently subscribed to this offer,” contact your team members to request an invitation to the existing AWS-linked organization. The **Set up your account** button is clickable, but Pinecone does not create a new AWS-linked organization.
7. Log in to your Pinecone account. Use the same authentication method as your existing Pinecone organization.
8. Select an organization from the list. You can only connect to organizations that are on the [Starter plan](https://www.pinecone.io/pricing/). Alternatively, you can opt to create a new organization.
9. Click **Connect to Pinecone** and follow the prompts.
Once your organization is connected and upgraded, you will receive a confirmation message. You will then immediately start paying for usage of your Pinecone indexes, including the serverless indexes that were free on the Starter plan. For more details about how costs are calculated, see [Understanding cost](/guides/manage-cost/understanding-cost).
### Pay through the Microsoft Marketplace
To upgrade your plan to Standard or Enterprise and pay through the Microsoft Marketplace, do the following:
1. In the Pinecone console, go to [Settings > Billing > Plans](https://app.pinecone.io/organizations/-/settings/billing/plans).
2. Click **Upgrade** in the **Standard** or **Enterprise** plan section.
3. Click **Billing through Azure**. This takes you to the [Pinecone listing](https://marketplace.microsoft.com/product/saas/pineconesystemsinc1688761585469.pineconesaas) in the Microsoft Marketplace.
4. Click **Get it now**.
5. Select the **Pinecone - Pay As You Go** plan.
6. Click **Subscribe**.
7. On the **Subscribe to Pinecone** page, select the required details and click **Review + subscribe**.
The billing unit listed does not reflect the actual cost or metering of costs for Pinecone. See the [Pinecone Pricing page](https://www.pinecone.io/pricing/) for accurate details.
8. Click **Subscribe**.
9. After the subscription is approved, click **Configure account now**. This redirects you to an Microsoft-specific Pinecone login page.
10. Log in to your Pinecone account. Use the same authentication method as your existing Pinecone organization.
11. Select an organization from the list. You can only connect to organizations that are on the [Starter plan](https://www.pinecone.io/pricing/). Alternatively, you can opt to create a new organization.
12. Click **Connect to Pinecone** and follow the prompts.
Once your organization is connected and upgraded, you will receive a confirmation message. You will then immediately start paying for usage of your Pinecone indexes, including the serverless indexes that were free on the Starter plan. For more details about how costs are calculated, see [Understanding cost](/guides/manage-cost/understanding-cost).
# Manage organization members
Source: https://docs.pinecone.io/guides/organizations/manage-organization-members
Add, invite, and manage members in your Pinecone organization, including assigning organization roles, changing permissions, and removing users.
This page shows how [organization owners](/guides/organizations/understanding-organizations#organization-roles) can add and manage organization members.
To assign and manage roles programmatically with the Admin API, or to manage roles for service accounts and API keys, see [Manage roles and access](/guides/production/manage-rbac).
For information about managing members at the **project-level**, see [Manage project members](/guides/projects/manage-project-members).
## Add a member to an organization
You can add members to your organization in the [Pinecone console](https://app.pinecone.io):
1. Go to [**Settings > Access > Members**](https://app.pinecone.io/organizations/-/settings/access/members).
2. In the **Invite by email** field, enter the member's email address.
3. Choose an [**Organization role**](/guides/organizations/understanding-organizations#organization-roles) for the member. The role determines the member's permissions within Pinecone.
4. Click **Invite**.
When you invite a member to join your organization, Pinecone sends them an email containing a link that enables them to gain access to the organization or project. If they already have a Pinecone account, they still receive an email, but they can also immediately view the project.
## Change a member's role
You can change a member's role in the [Pinecone console](https://app.pinecone.io):
1. Go to [**Settings > Access > Members**](https://app.pinecone.io/organizations/-/settings/access/members).
2. In the row of the member whose role you want to change, click **ellipsis (...) menu > Edit role**.
3. Select an [**Organization role**](/guides/organizations/understanding-organizations#organization-roles) for the member.
4. Click **Edit role**.
## Remove a member
You can remove a member from your organization in the [Pinecone console](https://app.pinecone.io):
1. Go to [**Settings > Access > Members**](https://app.pinecone.io/organizations/-/settings/access/members).
2. In the row of the member you want to remove, click **ellipsis (...) menu > Remove member**.
3. Click **Remove Member**.
To remove yourself from an organization, click the **Leave organization** button in your user's row and confirm.
# Manage service accounts at the organization-level
Source: https://docs.pinecone.io/guides/organizations/manage-service-accounts
Create and manage service accounts at the organization level in Pinecone for programmatic Admin API access, including client secrets and role assignment.
This feature is in [public preview](/release-notes/feature-availability) and available only on [Enterprise plans](https://www.pinecone.io/pricing/).
This page shows how [organization owners](/guides/organizations/understanding-organizations#organization-roles) can add and manage service accounts at the organization-level. Service accounts enable programmatic access to Pinecone's Admin API, which can be used to create and manage projects and API keys.
Once a service account is added at the organization-level, it can be added to a project. For more information, see [Manage service accounts at the project-level](/guides/projects/manage-service-accounts).
## Create a service account
You can create a service account in the [Pinecone console](https://app.pinecone.io):
1. Go to [**Settings > Access > Service accounts**](https://app.pinecone.io/organizations/-/settings/access/service-accounts).
2. Enter a **Name** for the service account.
3. Choose an [**Organization role**](/guides/organizations/understanding-organizations#organization-roles) for the service account. The role determines the service account's permissions within Pinecone.
4. Click **Create**.
5. Copy and save the **Client secret** in a secure place for future use. You will need the client secret to retrieve an access token.
You will not be able to see the client secret again after you close the dialog.
6. Click **Close**.
Once you have created a service account, [add it to a project](/guides/projects/manage-service-accounts#add-a-service-account-to-a-project) to allow it access to the project's resources.
## Retrieve an access token
To access the Admin API, you must provide an access token to authenticate. Retrieve the access token using the client secret of a service account, which was [provided at time of creation](#create-a-service-account).
You can retrieve an access token for a service account from the `https://login.pinecone.io/oauth/token` endpoint, as shown in the following example:
```bash curl theme={null}
curl "https://login.pinecone.io/oauth/token" \ # Note: Base URL is login.pinecone.io
-H "X-Pinecone-Api-Version: 2025-10" \
-H "Content-Type: application/json" \
-d '{
"grant_type": "client_credentials",
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET",
"audience": "https://api.pinecone.io/"
}'
```
The response will include an `access_token` field, which you can use to authenticate with the Admin API.
```
{
"access_token":"YOUR_ACCESS_TOKEN",
"expires_in":86400,
"token_type":"Bearer"
}
```
## Change a service account's role
You can change a service account's role in the [Pinecone console](https://app.pinecone.io):
1. Go to [**Settings > Access > Service accounts**](https://app.pinecone.io/organizations/-/settings/access/service-accounts).
2. In the row of the service account you want to update, click **ellipsis (...) menu > Manage**.
3. Select an [**Organization role**](/guides/organizations/understanding-organizations#organization-roles) for the service account.
4. Click **Update**.
## Update service account name
You can change a service account's name in the [Pinecone console](https://app.pinecone.io):
1. Go to [**Settings > Access > Service accounts**](https://app.pinecone.io/organizations/-/settings/access/service-accounts).
2. In the row of the service account you want to update, click **ellipsis (...) menu > Manage**.
3. Enter a new **Service account name**.
4. Click **Update**.
## Rotate a service account's secret
You can rotate a service account's client secret in the [Pinecone console](https://app.pinecone.io):
1. Go to [**Settings > Access > Service accounts**](https://app.pinecone.io/organizations/-/settings/access/service-accounts).
2. In the row of the service account you want to update, click **ellipsis (...) menu > Rotate secret**.
3. **Enter the service account name** to confirm.
4. Click **Rotate client secret**.
5. Copy and save the **Client secret** in a secure place for future use.
You will not be able to see the client secret again after you close the dialog.
6. Click **Close**.
## Delete a service account
Deleting a service account will remove it from all projects and will disrupt any applications using it to access Pinecone. You delete a service account in the [Pinecone console](https://app.pinecone.io):
1. Go to [**Settings > Access > Service accounts**](https://app.pinecone.io/organizations/-/settings/access/service-accounts).
2. In the row of the service account you want to update, click **ellipsis (...) menu > Delete**.
3. **Enter the service account name** to confirm.
4. Click **Delete service account**.
# Understanding organizations
Source: https://docs.pinecone.io/guides/organizations/understanding-organizations
Learn how Pinecone organizations group projects, share billing, and use organization roles to control member permissions and access to resources.
A Pinecone organization is a set of [projects](/guides/projects/understanding-projects) that use the same billing. Organizations allow one or more users to control billing and project permissions for all of the projects belonging to the organization. Each project belongs to an organization.
While an email address can be associated with multiple organizations, it cannot be used to create more than one organization. For information about managing organization members, see [Manage organization members](/guides/organizations/manage-organization-members).
## Projects in an organization
Each organization contains one or more projects that share the same organization owners and billing settings. Each project belongs to exactly one organization. If you need to move a project from one organization to another, [contact Support](https://app.pinecone.io/organizations/-/settings/support/ticket).
## Billing settings
All of the projects in an organization share the same billing method and settings. The billing settings for the organization are controlled by the organization owners.
Organization owners can update the billing contact information, update the payment method, and view and download invoices using the [Pinecone console](https://app.pinecone.io/organizations/-/settings/billing).
## Organization roles
Organization owners can manage access to their organizations and projects by assigning roles to organization members and service accounts. A role determines the permissions that a [principal](/guides/production/security-overview#role-based-access-controls-rbac) (a user, service account, or API key) has within Pinecone. The organization roles are as follows:
* **Organization owner** (`OrgOwner`): Full control over the organization, including billing, members, service accounts, security, and every project. Inherits [owner access](/guides/projects/understanding-projects#project-roles) to all projects in the organization.
* **Organization manager** (`OrgManager`): Can view organization details and create projects. Organization managers cannot manage billing, members, service accounts, or organization settings.
* **Organization member** (`OrgMember`): Can view organization details and access the projects they are added to. Organization members cannot create projects or manage organization settings. To grant project access, add the member to one or more projects and assign a [project role](/guides/projects/understanding-projects#project-roles); see [Manage project members](/guides/projects/manage-project-members).
* **Billing admin** (`OrgBillingAdmin`): Can view organization details and manage billing, subscriptions, and usage. Billing admins cannot manage members or organization settings, and they cannot manage projects unless they are also [project owners](/guides/projects/understanding-projects#project-roles).
The following table summarizes the permissions for each organization role:
| Permission | Owner | Manager | Member | Billing admin |
| -------------------------------------- | :---: | :-----: | :----: | :-----------: |
| View account details | ✓ | ✓ | ✓ | ✓ |
| Create projects | ✓ | ✓ | | |
| View billing and usage details | ✓ | | | ✓ |
| Manage billing details | ✓ | | | ✓ |
| Invite and remove organization members | ✓ | | | |
| Update organization member roles | ✓ | | | |
| Manage service accounts | ✓ | | | |
| Configure single sign-on (SSO) | ✓ | | | |
| Configure audit logs | ✓ | | | |
| Update organization name | ✓ | | | |
| Delete the organization | ✓ | | | |
## Organization single sign-on (SSO)
SSO allows organizations to manage their teams' access to Pinecone through their identity management solution. Once your integration is configured, you can specify a default role for teammates when they sign up.
For organizations that use SSO for authentication, console sessions are re-authenticated at least every 24 hours.
For more information, see [Configure single sign-on](/guides/production/configure-single-sign-on/okta).
SSO is available on Standard and Enterprise plans.
## Service accounts
This feature is in [public preview](/release-notes/feature-availability) and available only on [Enterprise plans](https://www.pinecone.io/pricing/).
[Service accounts](/guides/organizations/manage-service-accounts) enable programmatic access to Pinecone's Admin API, which can be used to create and manage projects and API keys.
Use service accounts to automate infrastructure management and integrate Pinecone into your deployment workflows, rather than through manual actions in the Pinecone console. Service accounts use the [organization roles](/guides/organizations/understanding-organizations#organization-roles) and [project role](/guides/projects/understanding-projects#project-roles) for permissioning, and provide a secure and auditable way to handle programmatic access.
## See also
* [Manage organization members](/guides/organizations/manage-organization-members)
* [Manage project members](/guides/projects/manage-project-members)
# CI/CD with Pinecone Local and GitHub Actions
Source: https://docs.pinecone.io/guides/production/automated-testing
Build a GitHub Actions CI/CD workflow with Pinecone Local to run automated integration tests against an in-memory emulator without touching production.
Pinecone Local is an in-memory Pinecone Database emulator available as a Docker image.
This page shows you how to build a CI/CD workflow with Pinecone Local and [GitHub Actions](https://docs.github.com/en/actions) to test your integration without connecting to your Pinecone account, affecting production data, or incurring any usage or storage fees.
Pinecone Local is not suitable for production. See [Limitations](#limitations) for details.
## Limitations
Pinecone Local has the following limitations:
* Pinecone Local uses the `2025-01` API version, which is not the latest stable version.
* Pinecone Local is available in Docker only.
* Pinecone Local is an in-memory emulator and is not suitable for production. Records loaded into Pinecone Local do not persist after it is stopped.
* Pinecone Local does not authenticate client requests. API keys are ignored.
* Max number of records per index: 100,000.
Pinecone Local does not currently support the following features:
* [Import from object storage](/guides/index-data/import-data)
* [Backup/restore of serverless indexes](/guides/manage-data/backups-overview)
* [Collections for pod-based indexes](/guides/indexes/pods/understanding-collections)
* [Namespace management](/guides/manage-data/manage-namespaces)
* [Pinecone Inference](/reference/api/introduction#inference)
* [Pinecone Assistant](/guides/assistant/overview)
## 1. Write your tests
Running code against Pinecone Local is just like running code against your Pinecone account, with the following differences:
* Pinecone Local does not authenticate client requests. API keys are ignored.
* The latest version of Pinecone Local uses [Pinecone API version](/reference/api/versioning) `2025-01` and requires [Python SDK](/reference/sdks/python/overview) `v6.x` or later, [Node.js SDK](/reference/sdks/node/overview) `v5.x` or later, [Java SDK](/reference/sdks/java/overview) `v4.x` or later, and [Go SDK](/reference/sdks/go/overview) `v3.x` or later.
Be sure to review the [limitations](#limitations) of Pinecone Local before using it for development or testing.
**Example**
The following example assumes that you have [started Pinecone Local without indexes](/guides/operations/local-development#database-emulator). It initializes a client, creates [an index for dense vectors](/guides/index-data/indexing-overview#indexes-with-dense-vectors) and [an index for sparse vectors](/guides/index-data/indexing-overview#indexes-with-sparse-vectors), upserts records into each, checks their record counts, and queries them.
```python Python theme={null}
from pinecone.grpc import PineconeGRPC, GRPCClientConfig
from pinecone import ServerlessSpec
# Initialize a client.
# API key is required, but the value does not matter.
# Host and port of the Pinecone Local instance
# is required when starting without indexes.
pc = PineconeGRPC(
api_key="pclocal",
host="http://localhost:5080"
)
# Create two indexes, one dense and one sparse
dense_index_name = "dense-index"
sparse_index_name = "sparse-index"
if not pc.has_index(dense_index_name):
dense_index_model = pc.create_index(
name=dense_index_name,
vector_type="dense",
dimension=2,
metric="cosine",
spec=ServerlessSpec(cloud="aws", region="us-east-1"),
deletion_protection="disabled",
tags={"environment": "development"}
)
print("Index model (dense):\n", dense_index_model)
if not pc.has_index(sparse_index_name):
sparse_index_model = pc.create_index(
name=sparse_index_name,
vector_type="sparse",
metric="dotproduct",
spec=ServerlessSpec(cloud="aws", region="us-east-1"),
deletion_protection="disabled",
tags={"environment": "development"}
)
print("\nIndex model (sparse):\n", sparse_index_model)
# Target each index, disabling tls
dense_index_host = pc.describe_index(name=dense_index_name).host
dense_index = pc.Index(host=dense_index_host, grpc_config=GRPCClientConfig(secure=False))
sparse_index_host = pc.describe_index(name=sparse_index_name).host
sparse_index = pc.Index(host=sparse_index_host, grpc_config=GRPCClientConfig(secure=False))
# Upsert records into the index (dense)
dense_index.upsert(
vectors=[
{
"id": "vec1",
"values": [1.0, -2.5],
"metadata": {"genre": "drama"}
},
{
"id": "vec2",
"values": [3.0, -2.0],
"metadata": {"genre": "documentary"}
},
{
"id": "vec3",
"values": [0.5, -1.5],
"metadata": {"genre": "documentary"}
}
],
namespace="example-namespace"
)
# Upsert records into the index (sparse)
sparse_index.upsert(
namespace="example-namespace",
vectors=[
{
"id": "vec1",
"sparse_values": {
"values": [1.7958984, 0.41577148, 2.828125, 2.8027344, 2.8691406, 1.6533203, 5.3671875, 1.3046875, 0.49780273, 0.5722656, 2.71875, 3.0820312, 2.5019531, 4.4414062, 3.3554688],
"indices": [822745112, 1009084850, 1221765879, 1408993854, 1504846510, 1596856843, 1640781426, 1656251611, 1807131503, 2543655733, 2902766088, 2909307736, 3246437992, 3517203014, 3590924191]
},
"metadata": {
"chunk_text": "AAPL reported a year-over-year revenue increase, expecting stronger Q3 demand for its flagship phones.",
"category": "technology",
"quarter": "Q3"
}
},
{
"id": "vec2",
"sparse_values": {
"values": [0.4362793, 3.3457031, 2.7714844, 3.0273438, 3.3164062, 5.6015625, 2.4863281, 0.38134766, 1.25, 2.9609375, 0.34179688, 1.4306641, 0.34375, 3.3613281, 1.4404297, 2.2558594, 2.2597656, 4.8710938, 0.5605469],
"indices": [131900689, 592326839, 710158994, 838729363, 1304885087, 1640781426, 1690623792, 1807131503, 2066971792, 2428553208, 2548600401, 2577534050, 3162218338, 3319279674, 3343062801, 3476647774, 3485013322, 3517203014, 4283091697]
},
"metadata": {
"chunk_text": "Analysts suggest that AAPL'\''s upcoming Q4 product launch event might solidify its position in the premium smartphone market.",
"category": "technology",
"quarter": "Q4"
}
},
{
"id": "vec3",
"sparse_values": {
"values": [2.6875, 4.2929688, 3.609375, 3.0722656, 2.1152344, 5.78125, 3.7460938, 3.7363281, 1.2695312, 3.4824219, 0.7207031, 0.0826416, 4.671875, 3.7011719, 2.796875, 0.61621094],
"indices": [8661920, 350356213, 391213188, 554637446, 1024951234, 1640781426, 1780689102, 1799010313, 2194093370, 2632344667, 2641553256, 2779594451, 3517203014, 3543799498, 3837503950, 4283091697]
},
"metadata": {
"chunk_text": "AAPL'\''s strategic Q3 partnerships with semiconductor suppliers could mitigate component risks and stabilize iPhone production",
"category": "technology",
"quarter": "Q3"
}
}
]
)
# Check the number of records in each index
print("\nIndex stats (dense):\n", dense_index.describe_index_stats())
print("\nIndex stats (sparse):\n", sparse_index.describe_index_stats())
# Query the index (dense) with a metadata filter
dense_response = dense_index.query(
namespace="example-namespace",
vector=[3.0, -2.0],
filter={"genre": {"$eq": "documentary"}},
top_k=1,
include_values=False,
include_metadata=True
)
print("\nDense query response:\n", dense_response)
# Query the index (sparse) with a metadata filter
sparse_response = sparse_index.query(
namespace="example-namespace",
sparse_vector={
"values": [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
"indices": [767227209, 1640781426, 1690623792, 2021799277, 2152645940, 2295025838, 2443437770, 2779594451, 2956155693, 3476647774, 3818127854, 4283091697]
},
filter={
"quarter": {"$eq": "Q4"}
},
top_k=1,
include_values=False,
include_metadata=True
)
print("/nSparse query response:\n", sparse_response)
# Delete the indexes
pc.delete_index(name=dense_index_name)
pc.delete_index(name=sparse_index_name)
```
```javascript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
// Initialize a client.
// API key is required, but the value does not matter.
// Host and port of the Pinecone Local instance
// is required when starting without indexes.
const pc = new Pinecone({
apiKey: 'pclocal',
controllerHostUrl: 'http://localhost:5080'
});
// Create two indexes, one dense and one sparse
const denseIndexName = 'dense-index';
const sparseIndexName = 'sparse-index';
const denseIndexModel = await pc.createIndex({
name: denseIndexName,
vectorType: 'dense',
dimension: 2,
metric: 'cosine',
spec: {
serverless: {
cloud: 'aws',
region: 'us-east-1'
}
},
deletionProtection: 'disabled',
tags: { environment: 'development' },
});
console.log('Index model (dense):', denseIndexModel);
const sparseIndexModel = await pc.createIndex({
name: sparseIndexName,
vectorType: 'sparse',
metric: 'dotproduct',
spec: {
serverless: {
cloud: 'aws',
region: 'us-east-1'
}
},
deletionProtection: 'disabled',
tags: { environment: 'development' },
});
console.log('\nIndex model (sparse):', sparseIndexModel);
// Target each index
const denseIndexHost = (await pc.describeIndex(denseIndexName)).host;
const denseIndex = await pc.index(denseIndexName, 'http://' + denseIndexHost);
const sparseIndexHost = (await pc.describeIndex(sparseIndexName)).host;
const sparseIndex = await pc.index(sparseIndexName, 'http://' + sparseIndexHost);
// Upsert records into the index (dense)
await denseIndex.namespace('example-namespace').upsert([
{
id: 'vec1',
values: [1.0, -2.5],
metadata: { genre: 'drama' },
},
{
id: 'vec2',
values: [3.0, -2.0],
metadata: { genre: 'documentary' },
},
{
id: 'vec3',
values: [0.5, -1.5],
metadata: { genre: 'documentary' },
}
]);
// Upsert records into the index (sparse)
await sparseIndex.namespace('example-namespace').upsert([
{
id: 'vec1',
sparseValues: {
indices: [822745112, 1009084850, 1221765879, 1408993854, 1504846510, 1596856843, 1640781426, 1656251611, 1807131503, 2543655733, 2902766088, 2909307736, 3246437992, 3517203014, 3590924191],
values: [1.7958984, 0.41577148, 2.828125, 2.8027344, 2.8691406, 1.6533203, 5.3671875, 1.3046875, 0.49780273, 0.5722656, 2.71875, 3.0820312, 2.5019531, 4.4414062, 3.3554688]
},
metadata: {
chunk_text: 'AAPL reported a year-over-year revenue increase, expecting stronger Q3 demand for its flagship phones.',
category: 'technology',
quarter: 'Q3'
}
},
{
id: 'vec2',
sparseValues: {
indices: [131900689, 592326839, 710158994, 838729363, 1304885087, 1640781426, 1690623792, 1807131503, 2066971792, 2428553208, 2548600401, 2577534050, 3162218338, 3319279674, 3343062801, 3476647774, 3485013322, 3517203014, 4283091697],
values: [0.4362793, 3.3457031, 2.7714844, 3.0273438, 3.3164062, 5.6015625, 2.4863281, 0.38134766, 1.25, 2.9609375, 0.34179688, 1.4306641, 0.34375, 3.3613281, 1.4404297, 2.2558594, 2.2597656, 4.8710938, 0.5605469]
},
metadata: {
chunk_text: "Analysts suggest that AAPL's upcoming Q4 product launch event might solidify its position in the premium smartphone market.",
category: 'technology',
quarter: 'Q4'
}
},
{
id: 'vec3',
sparseValues: {
indices: [8661920, 350356213, 391213188, 554637446, 1024951234, 1640781426, 1780689102, 1799010313, 2194093370, 2632344667, 2641553256, 2779594451, 3517203014, 3543799498, 3837503950, 4283091697],
values: [2.6875, 4.2929688, 3.609375, 3.0722656, 2.1152344, 5.78125, 3.7460938, 3.7363281, 1.2695312, 3.4824219, 0.7207031, 0.0826416, 4.671875, 3.7011719, 2.796875, 0.61621094]
},
metadata: {
chunk_text: "AAPL's strategic Q3 partnerships with semiconductor suppliers could mitigate component risks and stabilize iPhone production",
category: 'technology',
quarter: 'Q3'
}
}
]);
// Check the number of records in each index
console.log('\nIndex stats (dense):', await denseIndex.describeIndexStats());
console.log('\nIndex stats (sparse):', await sparseIndex.describeIndexStats());
// Query the index (dense) with a metadata filter
const denseQueryResponse = await denseIndex.namespace('example-namespace').query({
vector: [3.0, -2.0],
filter: {
'genre': {'$eq': 'documentary'}
},
topK: 1,
includeValues: false,
includeMetadata: true,
});
console.log('\nDense query response:', denseQueryResponse);
const sparseQueryResponse = await sparseIndex.namespace('example-namespace').query({
sparseVector: {
indices: [767227209, 1640781426, 1690623792, 2021799277, 2152645940, 2295025838, 2443437770, 2779594451, 2956155693, 3476647774, 3818127854, 4283091697],
values: [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
},
topK: 1,
includeValues: false,
includeMetadata: true
});
console.log('\nSparse query response:', sparseQueryResponse);
// Delete the index
await pc.deleteIndex(denseIndexName);
await pc.deleteIndex(sparseIndexName);
```
```java Java theme={null}
import com.google.protobuf.Struct;
import com.google.protobuf.Value;
import io.pinecone.clients.Index;
import io.pinecone.clients.Pinecone;
import io.pinecone.proto.DescribeIndexStatsResponse;
import org.openapitools.db_control.client.model.DeletionProtection;
import io.pinecone.unsigned_indices_model.QueryResponseWithUnsignedIndices;
import java.util.*;
public class PineconeLocalExample {
public static void main(String[] args) {
// Initialize a client.
// API key is required, but the value does not matter.
// When starting without indexes, disable TLS and
// provide the host and port of the Pinecone Local instance.
String host = "http://localhost:5080";
Pinecone pc = new Pinecone.Builder("pclocal")
.withHost(host)
.withTlsEnabled(false)
.build();
// Create two indexes, one dense and one sparse
String denseIndexName = "dense-index";
String sparseIndexName = "sparse-index";
HashMap tags = new HashMap<>();
tags.put("environment", "development");
pc.createServerlessIndex(
denseIndexName,
"cosine",
2,
"aws",
"us-east-1",
DeletionProtection.DISABLED,
tags
);
pc.createSparseServelessIndex(
sparseIndexName,
"aws",
"us-east-1",
DeletionProtection.DISABLED,
tags,
"sparse"
);
// Get index connection objects
Index denseIndexConnection = pc.getIndexConnection(denseIndexName);
Index sparseIndexConnection = pc.getIndexConnection(sparseIndexName);
// Upsert records into the index (dense)
Struct metaData1 = Struct.newBuilder()
.putFields("genre", Value.newBuilder().setStringValue("drama").build())
.build();
Struct metaData2 = Struct.newBuilder()
.putFields("genre", Value.newBuilder().setStringValue("documentary").build())
.build();
Struct metaData3 = Struct.newBuilder()
.putFields("genre", Value.newBuilder().setStringValue("documentary").build())
.build();
denseIndexConnection.upsert("vec1", Arrays.asList(1.0f, -2.5f), null, null, metaData1, "example-namespace");
denseIndexConnection.upsert("vec2", Arrays.asList(3.0f, -2.0f), null, null, metaData2, "example-namespace");
denseIndexConnection.upsert("vec3", Arrays.asList(0.5f, -1.5f), null, null, metaData3, "example-namespace");
// Upsert records into the index (sparse)
ArrayList indices1 = new ArrayList<>(Arrays.asList(
822745112L, 1009084850L, 1221765879L, 1408993854L, 1504846510L,
1596856843L, 1640781426L, 1656251611L, 1807131503L, 2543655733L,
2902766088L, 2909307736L, 3246437992L, 3517203014L, 3590924191L
));
ArrayList values1 = new ArrayList<>(Arrays.asList(
1.7958984f, 0.41577148f, 2.828125f, 2.8027344f, 2.8691406f,
1.6533203f, 5.3671875f, 1.3046875f, 0.49780273f, 0.5722656f,
2.71875f, 3.0820312f, 2.5019531f, 4.4414062f, 3.3554688f
));
Struct sparseMetaData1 = Struct.newBuilder()
.putFields("chunk_text", Value.newBuilder().setStringValue("AAPL reported a year-over-year revenue increase, expecting stronger Q3 demand for its flagship phones.").build())
.putFields("category", Value.newBuilder().setStringValue("technology").build())
.putFields("quarter", Value.newBuilder().setStringValue("Q3").build())
.build();
ArrayList indices2 = new ArrayList<>(Arrays.asList(
131900689L, 592326839L, 710158994L, 838729363L, 1304885087L,
1640781426L, 1690623792L, 1807131503L, 2066971792L, 2428553208L,
2548600401L, 2577534050L, 3162218338L, 3319279674L, 3343062801L,
3476647774L, 3485013322L, 3517203014L, 4283091697L
));
ArrayList values2 = new ArrayList<>(Arrays.asList(
0.4362793f, 3.3457031f, 2.7714844f, 3.0273438f, 3.3164062f,
5.6015625f, 2.4863281f, 0.38134766f, 1.25f, 2.9609375f,
0.34179688f, 1.4306641f, 0.34375f, 3.3613281f, 1.4404297f,
2.2558594f, 2.2597656f, 4.8710938f, 0.5605469f
));
Struct sparseMetaData2 = Struct.newBuilder()
.putFields("chunk_text", Value.newBuilder().setStringValue("Analysts suggest that AAPL'\\''s upcoming Q4 product launch event might solidify its position in the premium smartphone market.").build())
.putFields("category", Value.newBuilder().setStringValue("technology").build())
.putFields("quarter", Value.newBuilder().setStringValue("Q4").build())
.build();
ArrayList indices3 = new ArrayList<>(Arrays.asList(
8661920L, 350356213L, 391213188L, 554637446L, 1024951234L,
1640781426L, 1780689102L, 1799010313L, 2194093370L, 2632344667L,
2641553256L, 2779594451L, 3517203014L, 3543799498L,
3837503950L, 4283091697L
));
ArrayList values3 = new ArrayList<>(Arrays.asList(
2.6875f, 4.2929688f, 3.609375f, 3.0722656f, 2.1152344f,
5.78125f, 3.7460938f, 3.7363281f, 1.2695312f, 3.4824219f,
0.7207031f, 0.0826416f, 4.671875f, 3.7011719f, 2.796875f,
0.61621094f
));
Struct sparseMetaData3 = Struct.newBuilder()
.putFields("chunk_text", Value.newBuilder().setStringValue("AAPL'\\''s strategic Q3 partnerships with semiconductor suppliers could mitigate component risks and stabilize iPhone production").build())
.putFields("category", Value.newBuilder().setStringValue("technology").build())
.putFields("quarter", Value.newBuilder().setStringValue("Q3").build())
.build();
sparseIndexConnection.upsert("vec1", Collections.emptyList(), indices1, values1, sparseMetaData1, "example-namespace");
sparseIndexConnection.upsert("vec2", Collections.emptyList(), indices2, values2, sparseMetaData2, "example-namespace");
sparseIndexConnection.upsert("vec3", Collections.emptyList(), indices3, values3, sparseMetaData3, "example-namespace");
// Check the number of records each the index
DescribeIndexStatsResponse denseIndexStatsResponse = denseIndexConnection.describeIndexStats(null);
System.out.println("Index stats (dense):");
System.out.println(denseIndexStatsResponse);
DescribeIndexStatsResponse sparseIndexStatsResponse = sparseIndexConnection.describeIndexStats(null);
System.out.println("Index stats (sparse):");
System.out.println(sparseIndexStatsResponse);
// Query the index (dense) with a metadata filter
List queryVector = Arrays.asList(1.0f, 1.5f);
QueryResponseWithUnsignedIndices denseQueryResponse = denseIndexConnection.query(1, queryVector, null, null, null, "example-namespace", null, false, true);
System.out.println("Dense query response:");
System.out.println(denseQueryResponse);
// Query the index (sparse) with a metadata filter
List sparseIndices = Arrays.asList(
767227209L, 1640781426L, 1690623792L, 2021799277L, 2152645940L,
2295025838L, 2443437770L, 2779594451L, 2956155693L, 3476647774L,
3818127854L, 428309169L);
List sparseValues = Arrays.asList(
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f);
QueryResponseWithUnsignedIndices sparseQueryResponse = sparseIndexConnection.query(1, null, sparseIndices, sparseValues, null, "example-namespace", null, false, true);
System.out.println("Sparse query response:");
System.out.println(sparseQueryResponse);
// Delete the indexes
pc.deleteIndex(denseIndexName);
pc.deleteIndex(sparseIndexName);
}
}
```
```go Go theme={null}
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
"google.golang.org/protobuf/types/known/structpb"
)
func prettifyStruct(obj interface{}) string {
bytes, _ := json.MarshalIndent(obj, "", " ")
return string(bytes)
}
func main() {
ctx := context.Background()
// Initialize a client.
// No API key is required.
// Host and port of the Pinecone Local instance
// is required when starting without indexes.
pc, err := pinecone.NewClientBase(pinecone.NewClientBaseParams{
Host: "http://localhost:5080",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
// Create two indexes, one dense and one sparse
denseIndexName := "dense-index"
denseVectorType := "dense"
dimension := int32(2)
denseMetric := pinecone.Cosine
deletionProtection := pinecone.DeletionProtectionDisabled
denseIdx, err := pc.CreateServerlessIndex(ctx, &pinecone.CreateServerlessIndexRequest{
Name: denseIndexName,
VectorType: &denseVectorType,
Dimension: &dimension,
Metric: &denseMetric,
Cloud: pinecone.Aws,
Region: "us-east-1",
DeletionProtection: &deletionProtection,
Tags: &pinecone.IndexTags{"environment": "development"},
})
if err != nil {
log.Fatalf("Failed to create serverless index: %v", denseIdx.Name)
} else {
fmt.Printf("Successfully created serverless index: %v\n", denseIdx.Name)
}
sparseIndexName := "sparse-index"
sparseVectorType := "sparse"
sparseMetric := pinecone.Dotproduct
sparseIdx, err := pc.CreateServerlessIndex(ctx, &pinecone.CreateServerlessIndexRequest{
Name: sparseIndexName,
VectorType: &sparseVectorType,
Metric: &sparseMetric,
Cloud: pinecone.Aws,
Region: "us-east-1",
DeletionProtection: &deletionProtection,
Tags: &pinecone.IndexTags{"environment": "development"},
})
if err != nil {
log.Fatalf("Failed to create serverless index: %v", sparseIdx.Name)
} else {
fmt.Printf("\nSuccessfully created serverless index: %v\n", sparseIdx.Name)
}
// Get the index hosts
denseIdxModel, err := pc.DescribeIndex(ctx, denseIndexName)
if err != nil {
log.Fatalf("Failed to describe index \"%v\": %v", denseIndexName, err)
}
sparseIdxModel, err := pc.DescribeIndex(ctx, sparseIndexName)
if err != nil {
log.Fatalf("Failed to describe index \"%v\": %v", sparseIndexName, err)
}
// Target the indexes.
// Make sure to prefix the hosts with http:// to let the SDK know to disable tls.
denseIdxConnection, err := pc.Index(pinecone.NewIndexConnParams{Host: "http://" + denseIdxModel.Host, Namespace: "example-namespace"})
if err != nil {
log.Fatalf("Failed to create IndexConnection for Host: %v", err)
}
sparseIdxConnection, err := pc.Index(pinecone.NewIndexConnParams{Host: "http://" + sparseIdxModel.Host, Namespace: "example-namespace"})
if err != nil {
log.Fatalf("Failed to create IndexConnection for Host: %v", err)
}
// Upsert records into the index (dense)
denseMetadataMap1 := map[string]interface{}{
"genre": "drama",
}
denseMetadata1, err := structpb.NewStruct(denseMetadataMap1)
if err != nil {
log.Fatalf("Failed to create metadata map: %v", err)
}
denseMetadataMap2 := map[string]interface{}{
"genre": "documentary",
}
denseMetadata2, err := structpb.NewStruct(denseMetadataMap2)
if err != nil {
log.Fatalf("Failed to create metadata map: %v", err)
}
denseMetadataMap3 := map[string]interface{}{
"genre": "documentary",
}
denseMetadata3, err := structpb.NewStruct(denseMetadataMap3)
if err != nil {
log.Fatalf("Failed to create metadata map: %v", err)
}
denseVectors := []*pinecone.Vector{
{
Id: "vec1",
Values: &[]float32{1.0, -2.5},
Metadata: denseMetadata1,
},
{
Id: "vec2",
Values: &[]float32{3.0, -2.0},
Metadata: denseMetadata2,
},
{
Id: "vec3",
Values: &[]float32{0.5, -1.5},
Metadata: denseMetadata3,
},
}
denseCount, err := denseIdxConnection.UpsertVectors(ctx, denseVectors)
if err != nil {
log.Fatalf("Failed to upsert vectors: %v", err)
} else {
fmt.Printf("\nSuccessfully upserted %d vector(s)!\n", denseCount)
}
// Upsert records into the index (sparse)
sparseValues1 := pinecone.SparseValues{
Indices: []uint32{822745112, 1009084850, 1221765879, 1408993854, 1504846510, 1596856843, 1640781426, 1656251611, 1807131503, 2543655733, 2902766088, 2909307736, 3246437992, 3517203014, 3590924191},
Values: []float32{1.7958984, 0.41577148, 2.828125, 2.8027344, 2.8691406, 1.6533203, 5.3671875, 1.3046875, 0.49780273, 0.5722656, 2.71875, 3.0820312, 2.5019531, 4.4414062, 3.3554688},
}
sparseMetadataMap1 := map[string]interface{}{
"chunk_text": "AAPL reported a year-over-year revenue increase, expecting stronger Q3 demand for its flagship phones",
"category": "technology",
"quarter": "Q3",
}
sparseMetadata1, err := structpb.NewStruct(sparseMetadataMap1)
if err != nil {
log.Fatalf("Failed to create metadata map: %v", err)
}
sparseValues2 := pinecone.SparseValues{
Indices: []uint32{131900689, 592326839, 710158994, 838729363, 1304885087, 1640781426, 1690623792, 1807131503, 2066971792, 2428553208, 2548600401, 2577534050, 3162218338, 3319279674, 3343062801, 3476647774, 3485013322, 3517203014, 4283091697},
Values: []float32{0.4362793, 3.3457031, 2.7714844, 3.0273438, 3.3164062, 5.6015625, 2.4863281, 0.38134766, 1.25, 2.9609375, 0.34179688, 1.4306641, 0.34375, 3.3613281, 1.4404297, 2.2558594, 2.2597656, 4.8710938, 0.560546},
}
sparseMetadataMap2 := map[string]interface{}{
"chunk_text": "Analysts suggest that AAPL's upcoming Q4 product launch event might solidify its position in the premium smartphone market.",
"category": "technology",
"quarter": "Q4",
}
sparseMetadata2, err := structpb.NewStruct(sparseMetadataMap2)
if err != nil {
log.Fatalf("Failed to create metadata map: %v", err)
}
sparseValues3 := pinecone.SparseValues{
Indices: []uint32{8661920, 350356213, 391213188, 554637446, 1024951234, 1640781426, 1780689102, 1799010313, 2194093370, 2632344667, 2641553256, 2779594451, 3517203014, 3543799498, 3837503950, 4283091697},
Values: []float32{2.6875, 4.2929688, 3.609375, 3.0722656, 2.1152344, 5.78125, 3.7460938, 3.7363281, 1.2695312, 3.4824219, 0.7207031, 0.0826416, 4.671875, 3.7011719, 2.796875, 0.61621094},
}
sparseMetadataMap3 := map[string]interface{}{
"chunk_text": "AAPL's strategic Q3 partnerships with semiconductor suppliers could mitigate component risks and stabilize iPhone production",
"category": "technology",
"quarter": "Q3",
}
sparseMetadata3, err := structpb.NewStruct(sparseMetadataMap3)
if err != nil {
log.Fatalf("Failed to create metadata map: %v", err)
}
sparseVectors := []*pinecone.Vector{
{
Id: "vec1",
SparseValues: &sparseValues1,
Metadata: sparseMetadata1,
},
{
Id: "vec2",
SparseValues: &sparseValues2,
Metadata: sparseMetadata2,
},
{
Id: "vec3",
SparseValues: &sparseValues3,
Metadata: sparseMetadata3,
},
}
sparseCount, err := sparseIdxConnection.UpsertVectors(ctx, sparseVectors)
if err != nil {
log.Fatalf("Failed to upsert vectors: %v", err)
} else {
fmt.Printf("\nSuccessfully upserted %d vector(s)!\n", sparseCount)
}
// Check the number of records in each index
denseStats, err := denseIdxConnection.DescribeIndexStats(ctx)
if err != nil {
log.Fatalf("Failed to describe index: %v", err)
} else {
fmt.Printf("\nIndex stats (dense): %+v\n", prettifyStruct(*denseStats))
}
sparseStats, err := sparseIdxConnection.DescribeIndexStats(ctx)
if err != nil {
log.Fatalf("Failed to describe index: %v", err)
} else {
fmt.Printf("\nIndex stats (sparse): %+v\n", prettifyStruct(*sparseStats))
}
// Query the index (dense) with a metadata filter
queryVector := []float32{3.0, -2.0}
queryMetadataMap := map[string]interface{}{
"genre": map[string]interface{}{
"$eq": "documentary",
},
}
metadataFilter, err := structpb.NewStruct(queryMetadataMap)
if err != nil {
log.Fatalf("Failed to create metadata map: %v", err)
}
denseRes, err := denseIdxConnection.QueryByVectorValues(ctx, &pinecone.QueryByVectorValuesRequest{
Vector: queryVector,
TopK: 1,
MetadataFilter: metadataFilter,
IncludeValues: false,
IncludeMetadata: true,
})
if err != nil {
log.Fatalf("Error encountered when querying by vector: %v", err)
} else {
fmt.Printf("\nDense query response: %v\n", prettifyStruct(denseRes))
}
// Query the index (sparse) with a metadata filter
sparseValues := pinecone.SparseValues{
Indices: []uint32{767227209, 1640781426, 1690623792, 2021799277, 2152645940, 2295025838, 2443437770, 2779594451, 2956155693, 3476647774, 3818127854, 4283091697},
Values: []float32{1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0},
}
sparseRes, err := sparseIdxConnection.QueryByVectorValues(ctx, &pinecone.QueryByVectorValuesRequest{
SparseValues: &sparseValues,
TopK: 1,
IncludeValues: false,
IncludeMetadata: true,
})
if err != nil {
log.Fatalf("Error encountered when querying by vector: %v", err)
} else {
fmt.Printf("\nSparse query response: %v\n", prettifyStruct(sparseRes))
}
// Delete the indexes
err = pc.DeleteIndex(ctx, denseIndexName)
if err != nil {
log.Fatalf("Failed to delete index: %v", err)
} else {
fmt.Printf("\nIndex \"%v\" deleted successfully\n", denseIndexName)
}
err = pc.DeleteIndex(ctx, sparseIndexName)
if err != nil {
log.Fatalf("Failed to delete index: %v", err)
} else {
fmt.Printf("\nIndex \"%v\" deleted successfully\n", sparseIndexName)
}
}
```
```shell curl theme={null}
PINECONE_LOCAL_HOST="localhost:5080"
DENSE_INDEX_HOST="localhost:5081"
SPARSE_INDEX_HOST="localhost:5082"
# Create two indexes, one dense and one sparse
curl -X POST "http://$PINECONE_LOCAL_HOST/indexes" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"name": "dense-index",
"vector_type": "dense",
"dimension": 2,
"metric": "cosine",
"spec": {
"serverless": {
"cloud": "aws",
"region": "us-east-1"
}
},
"tags": {
"environment": "development"
},
"deletion_protection": "disabled"
}'
curl -X POST "http://$PINECONE_LOCAL_HOST/indexes" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"name": "sparse-index",
"vector_type": "sparse",
"metric": "dotproduct",
"spec": {
"serverless": {
"cloud": "aws",
"region": "us-east-1"
}
},
"tags": {
"environment": "development"
},
"deletion_protection": "disabled"
}'
# Upsert records into the index (dense)
curl -X POST "http://$DENSE_INDEX_HOST/vectors/upsert" \
-H "Content-Type: application/json" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"namespace": "example-namespace",
"vectors": [
{
"id": "vec1",
"values": [1.0, -2.5],
"metadata": {"genre": "drama"}
},
{
"id": "vec2",
"values": [3.0, -2.0],
"metadata": {"genre": "documentary"}
},
{
"id": "vec3",
"values": [0.5, -1.5],
"metadata": {"genre": "documentary"}
}
]
}'
# Upsert records into the index (sparse)
curl -X POST "http://$SPARSE_INDEX_HOST/vectors/upsert" \
-H "Content-Type: application/json" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"namespace": "example-namespace",
"vectors": [
{
"id": "vec1",
"sparseValues": {
"values": [1.7958984, 0.41577148, 2.828125, 2.8027344, 2.8691406, 1.6533203, 5.3671875, 1.3046875, 0.49780273, 0.5722656, 2.71875, 3.0820312, 2.5019531, 4.4414062, 3.3554688],
"indices": [822745112, 1009084850, 1221765879, 1408993854, 1504846510, 1596856843, 1640781426, 1656251611, 1807131503, 2543655733, 2902766088, 2909307736, 3246437992, 3517203014, 3590924191]
},
"metadata": {
"chunk_text": "AAPL reported a year-over-year revenue increase, expecting stronger Q3 demand for its flagship phones.",
"category": "technology",
"quarter": "Q3"
}
},
{
"id": "vec2",
"sparseValues": {
"values": [0.4362793, 3.3457031, 2.7714844, 3.0273438, 3.3164062, 5.6015625, 2.4863281, 0.38134766, 1.25, 2.9609375, 0.34179688, 1.4306641, 0.34375, 3.3613281, 1.4404297, 2.2558594, 2.2597656, 4.8710938, 0.5605469],
"indices": [131900689, 592326839, 710158994, 838729363, 1304885087, 1640781426, 1690623792, 1807131503, 2066971792, 2428553208, 2548600401, 2577534050, 3162218338, 3319279674, 3343062801, 3476647774, 3485013322, 3517203014, 4283091697]
},
"metadata": {
"chunk_text": "Analysts suggest that AAPL'\''s upcoming Q4 product launch event might solidify its position in the premium smartphone market.",
"category": "technology",
"quarter": "Q4"
}
},
{
"id": "vec3",
"sparseValues": {
"values": [2.6875, 4.2929688, 3.609375, 3.0722656, 2.1152344, 5.78125, 3.7460938, 3.7363281, 1.2695312, 3.4824219, 0.7207031, 0.0826416, 4.671875, 3.7011719, 2.796875, 0.61621094],
"indices": [8661920, 350356213, 391213188, 554637446, 1024951234, 1640781426, 1780689102, 1799010313, 2194093370, 2632344667, 2641553256, 2779594451, 3517203014, 3543799498, 3837503950, 4283091697]
},
"metadata": {
"chunk_text": "AAPL'\''s strategic Q3 partnerships with semiconductor suppliers could mitigate component risks and stabilize iPhone production",
"category": "technology",
"quarter": "Q3"
}
}
]
}'
# Check the number of records in each index
curl -X POST "http://$DENSE_INDEX_HOST/describe_index_stats" \
-H "Content-Type: application/json" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{}'
curl -X POST "http://$SPARSE_INDEX_HOST/describe_index_stats" \
-H "Content-Type: application/json" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{}'
# Query the index (dense) with a metadata filter
curl "http://$DENSE_INDEX_HOST/query" \
-H "Content-Type: application/json" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"vector": [3.0, -2.0],
"filter": {"genre": {"$eq": "documentary"}},
"topK": 1,
"includeMetadata": true,
"includeValues": false,
"namespace": "example-namespace"
}'
# Query the index (sparse) with a metadata filter
curl "http://$SPARSE_INDEX_HOST/query" \
-H "Content-Type: application/json" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"sparseVector": {
"values": [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
"indices": [767227209, 1640781426, 1690623792, 2021799277, 2152645940, 2295025838, 2443437770, 2779594451, 2956155693, 3476647774, 3818127854, 4283091697]
},
"filter": {"quarter": {"$eq": "Q4"}},
"namespace": "example-namespace",
"topK": 1,
"includeMetadata": true,
"includeValues": false
}'
# Delete the index
curl -X DELETE "http://$PINECONE_LOCAL_HOST/indexes/dense-index" \
-H "X-Pinecone-Api-Version: 2025-10"
curl -X DELETE "http://$PINECONE_LOCAL_HOST/indexes/sparse-index" \
-H "X-Pinecone-Api-Version: 2025-10"
```
## 2. Set up GitHub Actions
[Set up a GitHub Actions workflow](https://docs.github.com/en/actions/writing-workflows/quickstart) to do the following:
1. Pull the Pinecone Local Docker image.
2. Start a Pinecone Local instance for each test run.
3. Execute tests against the local instance.
4. Tear down the instance after tests complete.
Here's a sample GitHub Actions workflow that you can extend for your own needs:
```yaml theme={null}
name: CI/CD with Pinecone Local
on:
pull_request:
branches:
- main
push:
branches:
- main
jobs:
pc-local-tests:
name: Pinecone Local tests
runs-on: ubuntu-latest
services:
pc-local:
image: ghcr.io/pinecone-io/pinecone-local:latest
env:
PORT: 5080
ports:
- "5080-6000:5080-6000"
steps:
- name: Check out repository code
uses: actions/checkout@v4
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install "pinecone[grpc]"
- name: Run tests
run: |
pytest test/
```
## 3. Run your tests
GitHub Actions will automaticaly run your tests against Pinecone Local when the events you specified in your workflow occur.
For a list of the events that can trigger a workflow and more details about using GitHub Actions for CI/CD, see the [GitHub Actions documentation](https://docs.github.com/en/actions).
# Bring your own cloud (BYOC)
Source: https://docs.pinecone.io/guides/production/bring-your-own-cloud
Deploy Pinecone BYOC in your own AWS, GCP, or Azure account for data sovereignty, network isolation, and regional data residency requirements.
BYOC is in [public preview](/release-notes/feature-availability) on AWS, GCP, and Azure.
Pinecone BYOC (bring your own cloud) is designed for organizations with strict requirements around data sovereignty, network isolation, and data residency.
With BYOC, you deploy the Pinecone data plane in your own cloud account (AWS, GCP, or Azure), and you get the benefits of a managed service — upgrades, scaling, and maintenance — without giving up control of your data or infrastructure.
Pinecone never has direct access to your cloud account. Your vectors, metadata, and queries never leave your environment, and no inbound network access is required. An agent in your cluster pulls operations from Pinecone and executes them locally.
BYOC uses a split architecture:
* The data plane runs entirely in your cloud account within a dedicated VPC, storing and processing your vectors, executing queries, and managing index data in object storage (S3 on AWS, GCS on GCP, or Azure Blob Storage on Azure).
* The control plane is managed by Pinecone globally and handles index lifecycle management, authentication, billing, and user management, but never stores or processes your vectors.
For maintenance, the agent authenticates with Pinecone's control plane, pulls pending operations (upgrades, scaling, etc.), and executes them locally. All operations are stored as Kubernetes CRDs, providing a complete audit trail.
Only operational metrics (CPU, memory, latency) and traces are transmitted to Pinecone for monitoring; customer data is filtered out before transmission.
## Encryption and customer-managed keys
In the **standard Pinecone service**, [customer-managed encryption keys (CMEK)](/guides/production/configure-cmek) are how you connect Pinecone-managed storage to **your** AWS KMS keys through the Pinecone console.
In **BYOC**, your vectors and index data are stored in **your** cloud account (for example object storage, databases, and block volumes). You apply your cloud provider’s KMS to those resources using the same native controls you use for other workloads (key policies, rotation, and compliance programs such as PCI or ISO 27001). When you deploy with [pulumi-pinecone-byoc](https://github.com/pinecone-io/pulumi-pinecone-byoc), you can supply your KMS key where the template supports it; see that repository’s README for current options. This is not the console **CMEK** flow used for hosted projects.
## Prerequisites
Before deploying BYOC, ensure you have the following tools installed on your local machine:
| Tool | Purpose | Install |
| ------------ | ---------------------- | ---------------------------------------------------------------------------- |
| Python 3.12+ | Runtime | [python.org](https://www.python.org/downloads/) |
| uv | Package manager | [docs.astral.sh/uv](https://docs.astral.sh/uv/getting-started/installation/) |
| Pulumi | Infrastructure-as-code | [pulumi.com/docs/install](https://www.pulumi.com/docs/install/) |
| kubectl | Cluster access | [kubernetes.io](https://kubernetes.io/docs/tasks/tools/) |
You also need:
* The CLI for your cloud provider:
* **AWS**: [AWS CLI v2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
* **GCP**: [gcloud CLI](https://cloud.google.com/sdk/docs/install)
* **Azure**: [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli)
* A cloud account with admin-level permissions:
* **AWS**: `AdministratorAccess`. `PowerUserAccess` is not sufficient because BYOC creates IAM roles and policies.
* **GCP**: `roles/owner`. `roles/editor` is not sufficient because BYOC creates IAM service accounts and bindings.
* **Azure**: `Owner` on the subscription. `Contributor` is not sufficient because BYOC creates managed identities and role assignments.
* Sufficient cloud quota for the resources (the setup wizard validates this)
* A Pinecone API key from the Pinecone console.
* A Pinecone Enterprise plan (required for BYOC access)
If you install any new tools, open a new terminal session before proceeding so that your shell picks up the updated PATH and environment.
## Deploy BYOC
To deploy BYOC, follow these steps:
Run the bootstrap script from the BYOC deployment repository ([github.com/pinecone-io/pulumi-pinecone-byoc](https://github.com/pinecone-io/pulumi-pinecone-byoc)) to start the interactive setup wizard:
```bash theme={null}
curl -fsSL https://raw.githubusercontent.com/pinecone-io/pulumi-pinecone-byoc/main/bootstrap.sh | bash
```
You can also pre-select your cloud provider:
```bash theme={null}
# AWS
curl -fsSL https://raw.githubusercontent.com/pinecone-io/pulumi-pinecone-byoc/main/bootstrap.sh | bash -s -- --cloud aws
# GCP
curl -fsSL https://raw.githubusercontent.com/pinecone-io/pulumi-pinecone-byoc/main/bootstrap.sh | bash -s -- --cloud gcp
# Azure
curl -fsSL https://raw.githubusercontent.com/pinecone-io/pulumi-pinecone-byoc/main/bootstrap.sh | bash -s -- --cloud azure
```
The script selects your cloud provider, checks that required tools are installed, verifies your cloud credentials, then launches an interactive wizard that collects your configuration choices, validates your quotas, and generates a Pulumi project. No cloud resources are created during this step.
The wizard prompts you for the following:
| Prompt | Description | Default |
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- |
| **Cloud provider** | Select AWS, GCP, or Azure (skipped if pre-selected via `--cloud`). | - |
| **Pinecone API key** | Your API key from the Pinecone console (or uses `PINECONE_API_KEY` env var). | - |
| **Cloud credentials** | Validates credentials and displays your account/project/subscription ID. | - |
| **GCP project ID** | *(GCP only)* Your GCP project ID. | Detected from `gcloud` |
| **Azure subscription ID** | *(Azure only)* Your Azure subscription ID. | Detected from `az account show` |
| **Region** | Region for deployment. | `us-east-1` (AWS) / `us-central1` (GCP) / `eastus` (Azure) |
| **Availability zones** | Zones for high availability. Wizard fetches available options. | First two zones |
| **Custom AMI** | *(AWS only)* Custom AMI ID for EKS nodes. Leave blank for the default AWS AMI. | None |
| **VPC CIDR block** | IP range for your VPC/VNet. Choose a range that doesn't conflict with existing networks. | `10.0.0.0/16` (AWS/Azure) / `10.112.0.0/12` (GCP) |
| **Deletion protection** | Protect databases and storage from accidental deletion. | Enabled |
| **Network access** | Public access (connect from anywhere) or private only (requires PrivateLink on AWS, Private Service Connect on GCP, or Private Link on Azure). | Public enabled |
| **Resource tags/labels** | Custom tags (AWS/Azure) or labels (GCP) for cost tracking (e.g., `team=platform,env=prod`). | None |
| **Preflight checks** | Validates cloud quotas. If checks fail, request quota increases before proceeding. | - |
| **Project name** | Name for your deployment. | `pinecone-byoc` |
| **Pulumi backend** | Where to store state: local (`~/.pulumi` with passphrase) or Pulumi Cloud. | Local |
After completing the wizard, a Pulumi project is generated in your project directory.
The wizard creates a `Pulumi..yaml` file with configurable options. The options vary by cloud provider:
| Option | Description | Default |
| ----------------------- | --------------------------------------------------- | ------------------------------ |
| `pinecone-version` | Pinecone release version | - |
| `region` | AWS region | `us-east-1` |
| `availability-zones` | Availability zones for high availability | `["us-east-1a", "us-east-1b"]` |
| `vpc-cidr` | VPC IP range | `10.0.0.0/16` |
| `deletion-protection` | Protect RDS and S3 from accidental deletion | `true` |
| `public-access-enabled` | Enable public endpoint (`false` = PrivateLink only) | `true` |
| `custom-ami-id` | Custom AMI ID for EKS nodes | Default AWS AMI |
| `tags` | Custom tags for all AWS resources | `{}` |
| Option | Description | Default |
| ----------------------- | --------------------------------------------------------------- | ------------------------------------ |
| `gcp:project` | GCP project ID | - |
| `pinecone-version` | Pinecone release version | - |
| `region` | GCP region | `us-central1` |
| `availability-zones` | Zones for high availability | `["us-central1-a", "us-central1-b"]` |
| `vpc-cidr` | VPC IP range | `10.112.0.0/12` |
| `deletion-protection` | Protect AlloyDB and GCS from accidental deletion | `true` |
| `public-access-enabled` | Enable public endpoint (`false` = Private Service Connect only) | `true` |
| `labels` | Custom labels for all GCP resources | `{}` |
| Option | Description | Default |
| ----------------------- | ----------------------------------------------------------------------- | ------------- |
| `subscription-id` | Azure subscription ID | - |
| `pinecone-version` | Pinecone release version | - |
| `region` | Azure region | `eastus` |
| `availability-zones` | Zones for high availability | `["1", "2"]` |
| `vpc-cidr` | VNet IP range | `10.0.0.0/16` |
| `deletion-protection` | Protect PostgreSQL Flexible Server and storage from accidental deletion | `true` |
| `public-access-enabled` | Enable public endpoint (`false` = Private Link only) | `true` |
| `tags` | Custom tags for all Azure resources | `{}` |
To change configuration after initial setup, edit `Pulumi..yaml` and run `pulumi up`.
For advanced users who want to integrate BYOC into existing Pulumi infrastructure, the `pulumi-pinecone-byoc` package is available on [PyPI](https://pypi.org/project/pulumi-pinecone-byoc/). Install with cloud-specific dependencies:
```bash theme={null}
# For AWS
uv add 'pulumi-pinecone-byoc[aws]'
# For GCP
uv add 'pulumi-pinecone-byoc[gcp]'
# For Azure
uv add 'pulumi-pinecone-byoc[azure]'
```
Import the cluster class for your cloud provider:
```python theme={null}
# AWS
from pulumi_pinecone_byoc.aws import PineconeAWSCluster, PineconeAWSClusterArgs
# GCP
from pulumi_pinecone_byoc.gcp import PineconeGCPCluster, PineconeGCPClusterArgs
# Azure
from pulumi_pinecone_byoc.azure import PineconeAzureCluster, PineconeAzureClusterArgs
```
See the [repository README](https://github.com/pinecone-io/pulumi-pinecone-byoc#programmatic-usage) for full usage examples.
Deploy the generated Pulumi project to create your cloud resources:
```bash theme={null}
cd pinecone-byoc
pulumi up
```
Pulumi shows a preview of all resources to be created. Confirm to proceed. Provisioning takes approximately 25-30 minutes.
When complete, the output displays:
* Your BYOC **environment name** (used when creating indexes).
* The **kubectl command** to configure cluster access.
The deployment creates the following resources in your cloud account:
| Component | AWS | GCP | Azure |
| -------------------- | --------------------------------------------------------------- | --------------------------------------------------- | ------------------------------------------------ |
| **VPC / Networking** | VPC, public and private subnets, NAT gateways, internet gateway | VPC network, subnets, Cloud NAT, Cloud Router | VNet, subnets, NAT gateway |
| **Kubernetes** | EKS cluster with managed node groups | GKE cluster with node pools | AKS cluster with agent pools |
| **Object storage** | S3 buckets (data, WAL, backups) | GCS buckets (data, WAL, backups) | Blob Storage containers (data, WAL, backups) |
| **Database** | Aurora PostgreSQL (RDS) | AlloyDB | PostgreSQL Flexible Server |
| **Load balancing** | Network Load Balancer | Internal load balancer with Private Service Connect | Internal load balancer with Private Link Service |
| **DNS** | Route 53 hosted zone | Cloud DNS managed zone | Azure DNS zone |
| **TLS certificates** | AWS Certificate Manager | cert-manager | cert-manager |
| **IAM** | IAM roles and policies | Service accounts and Workload Identity | Managed identities and Workload Identity |
The initial deployment provisions 3 Kubernetes nodes. After setup, the cluster autoscales based on the services Pinecone deploys and your workload.
Configure `kubectl` to connect to your cluster using the command from the deployment output:
```bash theme={null}
aws eks update-kubeconfig --region --name
```
```bash theme={null}
gcloud container clusters get-credentials --region --project
```
```bash theme={null}
az aks get-credentials --resource-group --name
```
The above command configures your local `kubectl` tool to communicate with your Kubernetes cluster. You'll use cluster access for administrative tasks like viewing operations and troubleshooting. Creating indexes and reading/writing vectors still use the standard Pinecone API.
Verify all components are running:
```bash theme={null}
# Check that all pods are running
kubectl get pods -A | grep -E "(pinecone|pc-)"
```
All pods should show `Running` status. If any pods are in `Pending` or `CrashLoopBackOff`, check the [Troubleshooting](#troubleshooting) section.
You can also verify the cluster operations CRD is installed:
```bash theme={null}
kubectl get cluster-operations
```
It's normal to see "No resources found" on a fresh deployment. Operations appear here as Pinecone performs upgrades and other management tasks.
## Use BYOC
Once your BYOC environment is deployed, you can create indexes and read/write data using the standard Pinecone API.
### Control plane operations
Control plane operations like [creating](/reference/api/latest/control-plane/create_index), [listing](/reference/api/latest/control-plane/list_indexes), and [deleting](/reference/api/latest/control-plane/delete_index) indexes work via the standard Pinecone API regardless of your network access mode.
BYOC supports [dedicated read nodes](/guides/index-data/dedicated-read-nodes) indexes, but not on-demand indexes.
Use the environment name from the deployment output to create indexes in your BYOC environment. BYOC supports [dedicated read nodes](/guides/index-data/dedicated-read-nodes) indexes only.
```bash curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -X POST "https://api.pinecone.io/indexes" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Api-Key: $PINECONE_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10" \
-d '{
"name": "example-byoc-index",
"dimension": 1536,
"metric": "cosine",
"vector_type": "dense",
"spec": {
"byoc": {
"environment": "aws-us-east-1-26bf.byoc",
"read_capacity": {
"mode": "Dedicated",
"dedicated": {
"node_type": "b1",
"scaling": "Manual",
"manual": {
"shards": 1,
"replicas": 1
}
}
}
}
},
"deletion_protection": "disabled"
}'
```
```python Python theme={null}
from pinecone import Pinecone
from pinecone.db_control.models import ByocSpec
pc = Pinecone(api_key="YOUR_API_KEY")
pc.db.index.create(
name="example-byoc-index",
dimension=1536,
metric="cosine",
vector_type="dense",
spec=ByocSpec(
environment="aws-us-east-1-26bf.byoc",
read_capacity={
"mode": "Dedicated",
"dedicated": {
"node_type": "b1",
"scaling": "Manual",
"manual": {
"shards": 1,
"replicas": 1,
},
},
},
),
deletion_protection="disabled",
)
```
### Data plane operations
Data plane operations like [querying](/reference/api/latest/data-plane/query), [upserting](/reference/api/latest/data-plane/upsert), and [fetching](/reference/api/latest/data-plane/fetch) vectors depend on your network access mode.
BYOC does not support reading and writing data from the index browser in the Pinecone console.
Use the `host` URL from the Pinecone console or the [Describe an index](/reference/api/latest/control-plane/describe_index) API response. For example:
```
https://my-index-abc123.svc.us-east-1.byoc.pinecone.io
```
Connect from anywhere using the standard Pinecone SDK or API.
With public access disabled, you can only connect from within your VPC via private connectivity. You cannot use the Pinecone console for data plane operations (query, upsert, fetch), though control plane operations (create, delete, list indexes) still work.
After deployment, the Pulumi stack outputs include the service name needed to create a private endpoint for your cloud provider. Use this service name to set up private connectivity:
Follow the instructions in the AWS documentation to [create a VPC endpoint](https://docs.aws.amazon.com/vpc/latest/privatelink/create-interface-endpoint.html#create-interface-endpoint-aws) for connecting to your indexes via AWS PrivateLink.
For **Resource configurations**, use the VPC endpoint service name from the Pulumi stack outputs.
For **Network settings**, select the VPC for your BYOC deployment.
In **Additional settings**, select **Enable DNS name** to allow you to access your indexes using a DNS name.
Follow the instructions in the GCP documentation to [create a private endpoint](https://cloud.google.com/vpc/docs/configure-private-service-connect-services#create-endpoint) for connecting to your indexes via GCP Private Service Connect.
* Set the **Target service** to the service attachment from the Pulumi stack outputs.
* Copy the IP address of the private endpoint. You'll need it later.
Follow the instructions in the GCP documentation to [create a private DNS zone](https://cloud.google.com/dns/docs/zones#create-private-zone).
* Set the **DNS name** to the following:
```
.byoc.pinecone.io
```
* Select the same VPC network as the private endpoint.
Follow the instructions in the GCP documentation to [add a resource record set](https://cloud.google.com/dns/docs/records#add-rrset).
* Set the **DNS name** to **\***.
* Set the **Resource record type** to **A**.
* Set the **Ipv4 Address** to the IP address of the private endpoint.
Follow the instructions in the Azure documentation to [create a private endpoint](https://learn.microsoft.com/en-us/azure/private-link/create-private-endpoint-portal) for connecting to your indexes via Azure Private Link.
* Set the **Resource type** to `Microsoft.Network/privateLinkServices`.
* Select the Private Link Service name from the Pulumi stack outputs.
* Copy the IP address of the private endpoint. You'll need it later.
Follow the instructions in the Azure documentation to [create a private DNS zone](https://learn.microsoft.com/en-us/azure/dns/private-dns-getstarted-portal).
* Set the **Name** to the following:
```
.byoc.pinecone.io
```
* Link the zone to the VNet containing the private endpoint.
Follow the instructions in the Azure documentation to [add a record set](https://learn.microsoft.com/en-us/azure/dns/private-dns-getstarted-portal#create-an-additional-dns-record).
* Set the **Name** to **\***.
* Set the **Type** to **A**.
* Set the **IP address** to the IP address of the private endpoint.
Once configured, use the `private_host` URL from the Pinecone console or the [Describe an index](/reference/api/latest/control-plane/describe_index) API response. For example:
```
https://my-index-abc123.svc.private.us-east-1.byoc.pinecone.io
```
## Manage BYOC
### Operations and upgrades
Pinecone uses a pull-based model for cluster operations:
1. When upgrades, scaling, or maintenance are needed, Pinecone queues operations in the control plane.
2. An agent running in your cluster (deployed automatically during setup) continuously pulls pending operations.
3. Operations execute locally within your cluster.
4. Status is reported back to Pinecone for monitoring.
This model ensures Pinecone never needs direct access to your infrastructure. All operations are stored as Kubernetes CRDs, providing a complete audit trail.
### Monitoring
You can monitor your BYOC deployment through multiple channels:
View index metrics (read/write units, latency, storage) in the Pinecone console. Control plane operations and metrics work regardless of your network access mode.
To use Prometheus, configure your monitoring tool within your VPC to scrape metrics from the cluster. Your Prometheus instance must have network access to the BYOC VPC. The deployment output includes the metrics endpoint URL and port for configuration.
All cluster operations are persisted as Kubernetes CRDs for compliance and auditing:
```bash theme={null}
kubectl get cluster-operations
```
### Cleanup
To destroy your BYOC deployment:
Delete all BYOC indexes before destroying the cluster. Indexes cannot be properly terminated if the cluster is destroyed first.
```bash theme={null}
# 1. Delete all indexes via Pinecone API or console
# 2. Then destroy the infrastructure
pulumi destroy
```
If `deletion_protection` is enabled (the default), you must either disable it in `Pulumi..yaml` and run `pulumi up`, or manually delete protected resources via the cloud console before running `pulumi destroy`:
* **AWS**: RDS instances and S3 buckets
* **GCP**: AlloyDB instances and GCS buckets
* **Azure**: PostgreSQL Flexible Server instances and Storage accounts
## Reference
### Troubleshooting
Common issues and how to resolve them:
The setup wizard validates cloud quotas before deployment. If checks fail:
| Check | Resolution |
| ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| VPC / network quota | Request a limit increase via your cloud provider's quota console |
| Kubernetes cluster quota | Request an EKS, GKE, or AKS cluster limit increase |
| IP address quota | Release unused IPs or request a limit increase |
| Instance / machine type availability | Verify the required type is available in your region |
| vCPU quota (Azure) | Request a "Total Regional vCPUs" increase via the Azure Portal (minimum 8 required) |
| VM SKU availability (Azure) | Verify `Standard_D4s_v5` and L-series SKUs are available in your region |
| Resource providers (Azure) | Register required providers: `Microsoft.Compute`, `Microsoft.ContainerService`, `Microsoft.DBforPostgreSQL`, `Microsoft.Storage`, `Microsoft.Network`, `Microsoft.KeyVault`, `Microsoft.ManagedIdentity`, `Microsoft.Authorization` |
| Required APIs (GCP only) | Enable Compute Engine, GKE, AlloyDB, Cloud Storage, and Cloud DNS |
If `pulumi up` fails partway through:
```bash theme={null}
pulumi refresh # Sync state with actual resources
pulumi up # Retry deployment
```
Ensure your cloud credentials match the account where the cluster is deployed:
```bash theme={null}
aws sts get-caller-identity
```
```bash theme={null}
gcloud auth list
gcloud config get-value project
```
```bash theme={null}
az account show
```
If you destroyed the cluster before deleting indexes, indexes may be stuck in a "terminating" state. Contact [Pinecone support](https://app.pinecone.io/organizations/-/settings/support/ticket) for assistance.
For additional help, see the [GitHub Issues](https://github.com/pinecone-io/pulumi-pinecone-byoc/issues) for the deployment repository.
### Limitations
Some features available in the standard Pinecone service are not yet supported or have constraints in BYOC:
* Each organization can have up to 2 BYOC environments. To request an increase, contact [Pinecone support](https://app.pinecone.io/organizations/-/settings/support/ticket).
* [Integrated embedding and inference](/guides/index-data/indexing-overview#integrated-embedding), which relies on models hosted by Pinecone outside your cloud account.
* Reading and writing data from the index browser in the Pinecone console.
* Pinecone CLI data plane operations (queries, upserts, fetches). Control plane operations (create, list, delete indexes) work as expected.
* Imports from private cloud storage buckets, unless the bucket is in the same cloud account as your BYOC deployment.
* On-demand indexes (initial release supports DRN indexes only).
To [monitor with Prometheus](/guides/production/monitoring#monitor-with-prometheus), you must configure Prometheus within your VPC.
### FAQs
Answers to common questions about BYOC:
No. BYOC is designed so Pinecone never needs direct access to your infrastructure. Specifically:
* Pinecone does not need SSH, VPN, or inbound access to your cluster.
* You control cloud account boundaries, networking, and Kubernetes access.
* Operational changes run through explicit, software-mediated workflows.
* You don't open inbound firewall ports for Pinecone operations.
Operations are executed via a pull-based model where your cluster retrieves and runs operations locally. All communication is outbound from your cluster.
**Does not leave your cloud account:**
* Vectors, metadata, and index contents
* Query and upsert payloads
* Customer data
**Can leave your cloud account:**
* Operational metrics and traces (for example, CPU, memory, latency)
* Cluster health and operation status
Customer data is filtered out before transmission and never leaves your cloud account.
In the standard service, Pinecone manages all cloud resources and includes their cost in the service fee. In BYOC, you provision and pay for cloud resources directly through your own cloud account, providing greater control, data sovereignty, and access to available cloud credits or discounts.
You use API keys from the Pinecone console, just like with the standard Pinecone service. Authentication is handled by Pinecone's global control plane, and your data plane caches API keys locally. This means you manage users and API keys through the console as usual.
Data is stored and processed exclusively within your cloud account, with encryption at rest and in transit. You control at-rest encryption for the underlying resources (including KMS keys in your account) the same way you do for other infrastructure. Communication between the data plane and control plane is encrypted using TLS. Private connectivity (AWS PrivateLink, GCP Private Service Connect, or Azure Private Link) can be used for additional network isolation. For how this relates to hosted [CMEK](/guides/production/configure-cmek), see [Encryption and customer-managed keys](#encryption-and-customer-managed-keys).
BYOC is available on AWS, GCP, and Azure.
Indexes cannot be properly terminated if the cluster is destroyed first. Always delete indexes via the Pinecone API or console before running `pulumi destroy`.
Deploying a BYOC environment creates an internal project named `__SLI__` in your organization. This is used by Pinecone to enforce SLAs for your BYOC environment. Do not modify or delete this project.
### Pricing
BYOC pricing is based on provisioned resources (compute and storage) in your deployment, metered over time. Usage is measured by the Pinecone BYOC agent running in your cluster, which periodically reports the resources that are provisioned.
What you pay:
* Pinecone fees: Based on provisioned compute (vCPU and RAM) and storage (NVMe) resources
* Cloud provider fees: You pay your cloud provider directly for the underlying infrastructure (Kubernetes nodes, object storage, databases, networking, etc.)
Billing follows the agent heartbeat connection to Pinecone's control plane:
* When heartbeats are received, you are billed for the provisioned compute and storage the agent reports, even if the cluster is unhealthy.
* Short heartbeat interruptions (under 60 minutes) are treated as a grace period.
* If heartbeats are missing for more than 60 minutes, billing stops and the deployment is marked disconnected.
Billing is based on provisioned resources, not query volume. Resources that are running in your cluster are billed whether they are idle, actively processing queries, or experiencing errors.
# Configure audit logs
Source: https://docs.pinecone.io/guides/production/configure-audit-logs
Enable Pinecone audit logging to an Amazon S3 bucket to track user, service account, and API actions for compliance, security review, and WORM retention.
This page describes how to configure audit logs in Pinecone. Audit logs provide a detailed record of user, service account, and API actions that occur on the management and [control plane](/guides/get-started/database-architecture#control-plane) within Pinecone. Pinecone supports Amazon S3 as a destination for audit logs.
To enable and manage audit logs, you must be an [organization owner](/guides/organizations/understanding-organizations#organization-roles). This feature is available only on [Enterprise plans](https://www.pinecone.io/pricing/).
## Enable audit logs
1. Set up a [IAM policy and role in Amazon S3](/guides/operations/integrations/integrate-with-amazon-s3).
2. Go to [**Settings > Audit logs**](https://app.pinecone.io/organizations/-/settings/logging) in the Pinecone console.
3. Enter the **Role ARN** of the IAM role you created.
4. Enter the name of the Amazon S3 bucket you created.
**Targeting a subdirectory:** You can write audit logs to a specific subdirectory by entering `bucket-name/subdirectory-path` in the bucket name field. For example: `my-bucket/pinecone-logs`. Make sure your [IAM policy is configured for subdirectory access](/guides/operations/integrations/integrate-with-amazon-s3#targeting-a-subdirectory-optional).
5. Click **Enable audit logging**.
Once you enable audit logs, Pinecone will start writing logs to the S3 bucket. In your bucket, you will also see a file named `audit-log-access-test`, which is a test file that Pinecone writes to verify that it has the necessary permissions to write logs to the bucket.
## Make your audit-log bucket immutable (recommended)
Because audit logs are written to an Amazon S3 bucket you control, you can enforce write-once-read-many (WORM) immutability so that log files cannot be modified or deleted — including by your own administrators — for a retention period you define. This is recommended for compliance use cases.
Enable [S3 Object Lock](https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lock.html) in **compliance mode** with a retention period. Object Lock requires bucket versioning and, in general, must be enabled when the bucket is created — plan for it when you set up the [IAM policy and S3 bucket](/guides/operations/integrations/integrate-with-amazon-s3) above. Set the retention period to at least your required audit-log retention. Pinecone writes each log batch as a new, uniquely named file and does not modify or delete previously written logs.
Compliance mode is intentionally irreversible: until a retention period expires, objects cannot be deleted and the period cannot be shortened — not even by the root account. Logs already written to the bucket are therefore retained for the full period even if you later disable or remove the audit log integration.
## View audit logs
Logs are written to the S3 bucket approximately every 30 minutes. Each log batch will be saved into its own file as a JSON blob, keyed by the time of the log to be written. Only logs since the integration was created and enabled will be saved.
For more information about the log schema and captured events, see [Understanding security - Audit logs](/guides/production/security-overview#audit-logs).
## Edit audit log integration details
You can edit the details of the audit log integration in the Pinecone console:
1. Go to [**Settings > Audit logs**](https://app.pinecone.io/organizations/-/settings/logging).
2. Enter the new **Role ARN** or **AWS Bucket**.
3. Click **Update settings**.
## Disable audit logs
If you disable audit logs, logs not yet saved will be lost. You can disable audit logs in the Pinecone console:
1. Go to [**Settings > Audit logs**](https://app.pinecone.io/organizations/-/settings/logging).
2. Click the toggle next to **Audit logs are active**.
3. Click **Confirm**.
## Remove audit log integration
If you remove the audit log integration, logs not yet saved will be lost. You can remove the audit log integration in the Pinecone console:
1. Go to [**Settings > Audit logs**](https://app.pinecone.io/organizations/-/settings/logging).
2. At the top of the page, click the **ellipsis (...) menu > Remove integration**.
3. Click **Remove integration**.
# Configure customer-managed encryption keys
Source: https://docs.pinecone.io/guides/production/configure-cmek
Set up customer-managed encryption keys (CMEK) with AWS KMS to encrypt Pinecone data with keys you control, using IAM roles and key policies.
This guide applies to **hosted** Pinecone projects where Pinecone manages your infrastructure. If you use [Bring your own cloud (BYOC)](/guides/production/bring-your-own-cloud), you encrypt data with **your** cloud provider KMS on resources in **your** account; follow the BYOC guide and [pulumi-pinecone-byoc](https://github.com/pinecone-io/pulumi-pinecone-byoc) instead of the console CMEK flow below.
This page describes how to set up and use customer-managed encryption keys (CMEK) to secure data within a Pinecone project. CMEK allows you to encrypt your data using keys that you manage in your cloud provider's key management system (KMS). Pinecone supports CMEK using Amazon Web Services (AWS) KMS.
## Set up CMEK using AWS KMS
### Before you begin
The following steps assume you have:
* Access to the [AWS console](https://console.aws.amazon.com/console/home).
* A [Pinecone Enterprise plan](https://www.pinecone.io/pricing/).
### 1. Create a role
In the [AWS console](https://console.aws.amazon.com/console/home), create a role that Pinecone can use to access the AWS Key Management System (KMS) key. You can either grant Pinecone access to a key in your account, or if your customers provide their own keys, you can grant access to keys that are outside of your account.
1. Open the [Amazon Identity and Access Management (IAM) console](https://console.aws.amazon.com/iam/).
2. In the navigation pane, click **Roles**.
3. Click **Create role**.
4. In the **Trusted entity type** section, select **Custom trust policy**.
5. In the **Custom trust policy** section, enter one of the following JSON snippets.
Pick a snippet based on whether you want to allow Pinecone to assume a role from all regions or from explicit regions. Add an optional external ID for additional security. If you use an external ID, you must provide it to Pinecone when [adding a CMEK key](#add-a-key).
```jsonc JSON theme={null}
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowPineconeToAssumeIntoRoleFromExplicitRegionswithID",
"Effect": "Allow",
"Principal": {
"AWS": [
// Explicit role per Pinecone region. Replace XXXXXXXXXXXX with Pinecone's AWS account number.
"arn:aws:iam::XXXXXXXXXXXX:role/pinecone_cmek_access_us-east-1",
"arn:aws:iam::XXXXXXXXXXXX:role/pinecone_cmek_access_us-west-2",
"arn:aws:iam::XXXXXXXXXXXX:role/pinecone_cmek_access_eu-west-1",
"arn:aws:iam::XXXXXXXXXXXX:role/pinecone_cmek_access_eu-central-1",
"arn:aws:iam::XXXXXXXXXXXX:role/pinecone_cmek_access_ap-southeast-1"
]
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
// Optional. Replace with a UUID v4 for additional security. If you use an external ID, you must provide it to Pinecone when adding an API key.
"sts:ExternalId": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
}
}
}
]
}
```
```jsonc JSON theme={null}
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowPineconeToAssumeIntoRoleFromExplicitRegions",
"Effect": "Allow",
"Principal": {
"AWS": [
// Explicit role per Pinecone region. Replace XXXXXXXXXXXX with Pinecone's AWS account number.
"arn:aws:iam::XXXXXXXXXXXX:role/pinecone_cmek_access_us-east-1",
"arn:aws:iam::XXXXXXXXXXXX:role/pinecone_cmek_access_us-west-2",
"arn:aws:iam::XXXXXXXXXXXX:role/pinecone_cmek_access_eu-west-1",
"arn:aws:iam::XXXXXXXXXXXX:role/pinecone_cmek_access_eu-central-1",
"arn:aws:iam::XXXXXXXXXXXX:role/pinecone_cmek_access_ap-southeast-1"
]
},
"Action": "sts:AssumeRole"
}
]
}
```
```jsonc JSON theme={null}
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowPineconeToAssumeIntoRoleFromAllRegions",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
// Optional. Replace with a UUID v4 for additional security. If you use an external ID, you must provide it to Pinecone when adding an API key.
"sts:ExternalId": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
},
"StringLike": {
// Replace XXXXXXXXXXXX with Pinecone's AWS account number.
"aws:PrincipalArn": "arn:aws:iam::XXXXXXXXXXXX:role/pinecone_cmek_access_*"
}
}
}
]
}
```
Replace `XXXXXXXXXXXX` with Pinecone's AWS account number, which can be found by going to [**Manage > CMEK**](https://app.pinecone.io/organizations/-/projects/-/cmek-encryption) in the Pinecone console and clicking **Add CMEK**.
6. Click **Next**.
7. Keep the default permissions as is and click **Next**.
8. Enter a **Role name** and click **Create role**.
9. Copy the **Role ARN** (e.g., `arn:aws:iam::XXXXXX:role/YYYYYY`). This will be used to [create a CMEK-enabled project](#3-create-a-cmek-enabled-project).
1. Open the [Amazon Identity and Access Management (IAM) console](https://console.aws.amazon.com/iam/).
2. In the navigation pane, click **Roles**.
3. Click **Create role**.
4. In the **Trusted entity type** section, select **Custom trust policy**.
5. In the **Custom trust policy** section, enter the following JSON:
```json JSON theme={null}
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"kms:Decrypt",
"kms:Encrypt"
],
"Resource": "arn:aws:kms:*:XXXXXX:key/*"
}
]
}
```
* Replace `XXXXXX` with the account ID of the customer who owns the key.
* Add a `Statement` array for each customer account ID.
6. Click **Next**.
7. Keep the default permissions as is and click **Next**.
8. Enter a **Role name** and click **Create role**.
9. Copy the **Role ARN** (e.g., `arn:aws:iam::XXXXXX:role/YYYYYY`). This will be used to [create a CMEK-enabled project](#3-create-a-cmek-enabled-project).
### 2. Create an AWS KMS key
In the [AWS console](https://console.aws.amazon.com/console/home), create the KMS key that Pinecone will use to encrypt your data:
1. Open the [Amazon Key Management Service (KMS) console](https://console.aws.amazon.com/kms/home).
2. In the navigation pane, click **Customer managed keys**.
3. Click **Create key**.
4. In the **Key type** section, select **Symmetric**.
5. In the **Key usage** section, select **Encrypt and decrypt**.
6. Under **Advanced options > Key material origin**, select **KMS**.
7. In the **Regionality** section, select **Single-Region key**.
You can create a multi-regional key to safeguard against data loss in case of regional failure. However, Pinecone only accepts one Key ARN per project. If you set a multi-regional key and need to change the Key ARN to switch region, please [contact Support](https://app.pinecone.io/organizations/-/settings/support/ticket) for help.
8. Click **Next**.
9. Enter an **Alias** and click **Next**.
10. Keep the default administrators as is and click **Next**.
11. Select the [role you created](#1-create-a-role) from the **Key users** list and click **Next**.
12. Click **Finish**.
13. Copy the **Key ARN** (e.g., `arn:aws:kms:us-east-1:XXXXXXX:key/YYYYYYY`). This will be used to [create a CMEK-enabled project](#create-a-cmek-enabled-project).
**AWS KMS automatic key rotation is supported.** Pinecone references the Key ARN, not the underlying key material. As long as the Key ARN remains unchanged and accessible, you can perform key rotations inside AWS KMS without making any changes in Pinecone.
### 3. Create a CMEK-enabled project
Once your [role and key is configured](#set-up-cmek-using-aws-kms), you can create a CMEK-enabled project using the Pinecone console:
1. Go to [**Settings > Organization settings > Projects**](https://app.pinecone.io/organizations/-/settings/projects).
2. Click **+Create project**.
3. Enter a **Name**.
4. Select **Encrypt with Customer Managed Encryption Key**.
5. Click **Create project**.
6. Copy and save the generated API key in a secure place for future use.
You will not be able to see the API key again after you close the dialog.
7. Click **Close**.
## Add a key
To start encrypting your data with a customer-managed key, you need to add the key to the [CMEK-enabled project](#3-create-a-cmek-enabled-project) using the Pinecone console:
1. Go to [**Manage > CMEK**](https://app.pinecone.io/organizations/-/projects/-/cmek-encryption) for the CMEK-enabled project.
2. Click **Add CMEK**.
You can only add one key per project, and you cannot change the key in Pinecone once it is set.
3. Enter a **Key name**.
4. Enter the **Role ARN** for the [role you created](#1-create-a-role).
5. Enter a **Key ARN** for the [key you created](#2-create-a-aws-kms-key).
6. If you [created a role](#1-create-a-role) with an external ID, enter the **External ID**. If not, leave this field blank.
7. Click **Create key**.
## Delete a key
Before a key can be deleted from a project, all indexes in the project must be deleted. Then, you can delete the key using the Pinecone console:
1. Go to the [Manage > CMEK tab](https://app.pinecone.io/organizations/-/projects/-/cmek-encryption) for the project in which the key was created.
2. For the key you want to delete, click the **ellipsis (...) menu > Delete**.
3. Enter the key name to confirm deletion.
4. Click **Delete key**.
## Limitations
* CMEK can be enabled for serverless indexes in AWS regions only.
* [Backups](/guides/manage-data/back-up-an-index) are unavailable for indexes created in a CMEK-enabled project.
* You cannot change a key once it is set.
* You can add only one key per project.
# Configure Private Endpoints
Source: https://docs.pinecone.io/guides/production/configure-private-endpoints
Configure Pinecone Private Endpoints with AWS PrivateLink or Azure Private Link to keep index traffic off the public internet and secure VPCs.
This page describes how to create and use [Private Endpoints](/guides/production/security-overview#private-endpoints) to connect to Pinecone through AWS PrivateLink or Azure Private Link, keeping your traffic private from the public internet.
## Use Private Endpoints with Pinecone
### Before you begin
The following steps assume you have:
* Access to the [AWS console](https://console.aws.amazon.com/console/home).
* [Created an Amazon VPC](https://docs.aws.amazon.com/vpc/latest/userguide/create-vpc.html#create-vpc-and-other-resources) in the same AWS [region](/guides/index-data/create-an-index#cloud-regions) as the index you want to connect to. You can optionally enable DNS hostnames and resolution, if you want your VPC to automatically discover the DNS CNAME for your PrivateLink and do not want to configure a CNAME.
* To [configure the routing](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/routing-to-vpc-interface-endpoint.html) yourself, use one of Pinecone's DNS entry for the corresponding region:
| Index region | Pinecone DNS entry |
| ---------------------------- | -------------------------------------- |
| `us-east-1` (N. Virginia) | `*.private.aped-4627-b74a.pinecone.io` |
| `us-west-2` (Oregon) | `*.private.apw5-4e34-81fa.pinecone.io` |
| `eu-west-1` (Ireland) | `*.private.apu-57e2-42f6.pinecone.io` |
| `eu-central-1` (Frankfurt) | `*.private.apec-a2ee-38c6.pinecone.io` |
| `ap-southeast-1` (Singapore) | `*.private.aps-d9bb-582b.pinecone.io` |
* Access to the [Azure portal](https://portal.azure.com).
* [Created an Azure VNet](https://learn.microsoft.com/en-us/azure/virtual-network/quick-create-portal) in the same [region](/guides/index-data/create-an-index#cloud-regions) as the index you want to connect to.
* A subnet with **Private endpoint network policies** set to **Disabled**. This is required for Azure Private Endpoints.
* DNS resolution for private endpoints requires a manual setup step after creating the endpoint (unlike AWS, where DNS can be auto-configured). See the [DNS setup note below](#1-create-a-private-endpoint-in-your-cloud-provider).
| Index region | Pinecone DNS entry |
| -------------------- | ----------------------------------------------- |
| `eastus2` (Virginia) | `*.private.eastus2-5e25.prod-azure.pinecone.io` |
* A [Pinecone Enterprise plan](https://www.pinecone.io/pricing/).
* [Created a serverless index](/guides/index-data/create-an-index#create-a-serverless-index) in the same [region](/guides/index-data/create-an-index#cloud-regions) as your VPC or VNet.
Private Endpoints are configured at the project-level and you can add up to 10 endpoints per project. If you have multiple projects in your organization, Private Endpoints need to be set up separately for each.
### 1. Create a private endpoint in your cloud provider
In the [AWS console](https://console.aws.amazon.com/console/home):
1. Open the [Amazon VPC console](https://console.aws.amazon.com/vpc/).
2. In the navigation pane, click **Endpoint**.
3. Click **Create endpoint**.
4. For **Service category**, select **Other endpoint services**.
5. In **Service settings**, enter the **Service name**, based on the region your Pinecone index is in:
| Index region | Service name |
| ---------------------------- | -------------------------------------------------------------- |
| `us-east-1` (N. Virginia) | `com.amazonaws.vpce.us-east-1.vpce-svc-05ef6f1f0b9130b54` |
| `us-west-2` (Oregon) | `com.amazonaws.vpce.us-west-2.vpce-svc-04ecb9a0e0d5aab01` |
| `eu-west-1` (Ireland) | `com.amazonaws.vpce.eu-west-1.vpce-svc-03c6b7e17ff02a70f` |
| `eu-central-1` (Frankfurt) | `com.amazonaws.vpce.eu-central-1.vpce-svc-037997ff6b3d25e34` |
| `ap-southeast-1` (Singapore) | `com.amazonaws.vpce.ap-southeast-1.vpce-svc-0c12f00812e786068` |
6. Click **Verify service**.
7. Select the **VPC** to host the endpoint.
8. (Optional) In **Additional settings**, **Enable DNS name**.
The enables you to access our service with the DNS name we configure. An additional CNAME record is needed if you disable this option.
9. Select the **Subnets** and **Subnet ID** for the endpoint.
10. Select the **Security groups** to apply to the endpoint.
11. Click **Create endpoint**.
12. Copy the **VPC endpoint ID** (e.g., `vpce-XXXXXXX`).
This will be used to [add a Private Endpoint in Pinecone](#2-add-a-private-endpoint-in-pinecone).
In the [Azure portal](https://portal.azure.com):
1. Search for **Private Link** and select **Private Link Center**.
2. In the navigation pane, click **Private endpoints**.
3. Click **Create**.
4. Select your **Subscription** and **Resource group**.
5. Enter a **Name** for the private endpoint and select the **Region** matching your Pinecone index.
6. Click **Next: Resource**.
7. For **Connection method**, select **Connect to an Azure resource by resource ID or alias**.
8. Enter the **Resource ID or alias** for Pinecone's Private Link Service, based on the region your Pinecone index is in:
| Index region | Private Link Service alias |
| -------------------- | -------------------------------------------------------------------------------- |
| `eastus2` (Virginia) | `pinecone.bdbc7759-0243-46c1-af51-794c4602745b.eastus2.azure.privatelinkservice` |
9. Click **Next: Virtual Network**.
10. Select the **Virtual network** and **Subnet** for the private endpoint.
11. Click **Next: DNS**. Skip the DNS integration tab (you will configure DNS manually after setup).
12. Click **Next: Tags**.
13. Click **Review + create**, then **Create**.
14. Once the private endpoint is created, open it and copy the **Resource ID** from the **Properties** tab (or the **Overview** tab — it's the `/subscriptions/…/privateEndpoints/` ARM ID).
This will be used to [add a Private Endpoint in Pinecone](#2-add-a-private-endpoint-in-pinecone).
After creating the private endpoint, configure DNS so that `*.private.{subdomain}.pinecone.io` resolves to your private endpoint's IP address:
1. Find your private endpoint's IP address: in the Azure portal, open your private endpoint, go to **Overview**, and note the **Private IP address** (e.g., `172.30.0.6`).
2. Create an [Azure Private DNS Zone](https://learn.microsoft.com/en-us/azure/dns/private-dns-getstarted-portal) named `private.{subdomain}.pinecone.io` (e.g., `private.eastus2-5e25.prod-azure.pinecone.io`). You can find the `{subdomain}` in your index's host URL — it's the portion after `svc.` and before `.pinecone.io`.
3. [Link the zone](https://learn.microsoft.com/en-us/azure/dns/private-dns-virtual-network-links) to the VNet where your private endpoint is created.
4. Add a **wildcard A record** (`*`) pointing to your private endpoint's IP address.
### 2. Add a Private Endpoint in Pinecone
To add a Private Endpoint using the [Pinecone console](https://app.pinecone.io/organizations/-/projects):
1. Select your project.
2. Go to **Manage > Network**.
3. Click **Add a connection**.
4. Select your cloud provider and region.
Only indexes in the selected region in this project will be affected.
5. Click **Next**.
6. Enter the endpoint ID you copied in the [section above](#1-create-a-private-endpoint-in-your-cloud-provider):
* **AWS**: The VPC endpoint ID (e.g., `vpce-XXXXXXX`)
* **Azure**: The private endpoint's ARM Resource ID (e.g., `/subscriptions//resourceGroups//providers/Microsoft.Network/privateEndpoints/`)
7. Click **Next**.
8. (optional) To **enable private endpoint access only**, turn the toggle on.
This can also be enabled later. For more information, see [Manage internet access to your project](#manage-internet-access-to-your-project).
9. Click **Finish setup**.
Private Endpoints only affect [data plane](/reference/api/latest/data-plane) access. [Control plane](/reference/api/latest/control-plane) access will continue over the public internet.
## Read and write data
Once your private endpoint is configured, you can run data operations against an index as usual, but you must target the index using its private endpoint URL. The only difference in the URL is that `.svc.` is changed to `.svc.private.`.
You can get the private endpoint URL for an index from the Pinecone console or API.
To get the private endpoint URL for an index from the Pinecone console:
1. Open the [Pinecone console](https://app.pinecone.io/organizations/-/projects).
2. Select the project containing the index.
3. Select the index.
4. Copy the URL under **PRIVATE ENDPOINT**.
To get the private endpoint URL for an index from the API, use the [`describe_index`](/reference/api/latest/control-plane/describe_index) operation, which returns the private endpoint URL as the `private_host` value:
```JavaScript JavaScript theme={null}
import { Pinecone } from '@pinecone-database/pinecone';
const pc = new Pinecone({ apiKey: 'YOUR_API_KEY' });
await pc.describeIndex('docs-example');
```
```go Go theme={null}
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/pinecone-io/go-pinecone/v4/pinecone"
)
func prettifyStruct(obj interface{}) string {
bytes, _ := json.MarshalIndent(obj, "", " ")
return string(bytes)
}
func main() {
ctx := context.Background()
pc, err := pinecone.NewClient(pinecone.NewClientParams{
ApiKey: "YOUR_API_KEY",
})
if err != nil {
log.Fatalf("Failed to create Client: %v", err)
}
idx, err := pc.DescribeIndex(ctx, "docs-example")
if err != nil {
log.Fatalf("Failed to describe index \"%v\": %v", idx.Name, err)
} else {
fmt.Printf("index: %v\n", prettifyStruct(idx))
}
}
```
```bash curl theme={null}
PINECONE_API_KEY="YOUR_API_KEY"
curl -i -X GET "https://api.pinecone.io/indexes/docs-example" \
-H "Api-Key: YOUR_API_KEY" \
-H "X-Pinecone-Api-Version: 2025-10"
```
The response includes the private endpoint URL as the `private_host` value:
```json JavaScript {6} theme={null}
{
name: 'docs-example',
dimension: 1536,
metric: 'cosine',
host: 'docs-example-jl7boae.svc.aped-4627-b74a.pinecone.io',
privateHost: 'docs-example-jl7boae.svc.private.aped-4627-b74a.pinecone.io',
deletionProtection: 'disabled',
tags: { environment: 'production' },
embed: undefined,
spec: {
byoc: undefined,
pod: undefined,
serverless: { cloud: 'aws', region: 'us-east-1' }
},
status: { ready: true, state: 'Ready' },
vectorType: 'dense'
}
```
```go Go {5} theme={null}
index: {
"name": "docs-example",
"dimension": 1536,
"host": "docs-example-jl7boae.svc.aped-4627-b74a.pinecone.io",
"private_host": "docs-example-jl7boae.svc.private.aped-4627-b74a.pinecone.io",
"metric": "cosine",
"deletion_protection": "disabled",
"spec": {
"serverless": {
"cloud": "aws",
"region": "us-east-1"
}
},
"status": {
"ready": true,
"state": "Ready"
},
"tags": {
"environment": "production"
}
}
```
```json curl {12} theme={null}
{
"id": "025117b3-e683-423c-b2d1-6d30fbe5027f",
"vector_type": "dense",
"name": "docs-example",
"metric": "cosine",
"dimension": 1536,
"status": {
"ready": true,
"state": "Ready"
},
"host": "docs-example-jl7boae.svc.aped-4627-b74a.pinecone.io",
"private_host": "docs-example-jl7boae.svc.private.aped-4627-b74a.pinecone.io",
"spec": {
"serverless": {
"region": "us-east-1",
"cloud": "aws"
}
},
"deletion_protection": "disabled",
"tags": {
"environment": "production"
}
```
If you run data operations against an index from outside the Private Endpoint, you will get an `Unauthorized` response.
## Manage internet access to your project
Once your Private Endpoint is configured, you can turn off internet access to your project. To enable private endpoint access only:
1. Open the [Pinecone console](https://app.pinecone.io/organizations/-/projects).
2. Select your project.
3. Go to **Network > Access**.
4. Turn the **Private endpoint access only** toggle on.
This will turn off internet access to the project. This can be turned off at any point.
This access control is set at the *project-level* and can unintentionally affect Pinecone indexes that communicate via the internet in the same project. Only indexes communicating through Private Endpoints will continue to work.
## Manage Private Endpoints
In addition to [creating Private Endpoints](#2-add-a-private-endpoint-in-pinecone), you can also:
* [View Private Endpoints](#view-private-endpoints)
* [Delete a Private Endpoint](#delete-a-private-endpoint)
### View Private Endpoints
To view Private Endpoints using the [Pinecone console](https://app.pinecone.io/organizations/-/projects):
1. Select your project.
2. Go to **Manage > Network**.
A list of Private Endpoints displays with the associated endpoint ID and cloud provider.
### Delete a Private Endpoint
To delete a Private Endpoint using the [Pinecone console](https://app.pinecone.io/organizations/-/projects):
1. Select your project.
2. Go to **Manage > Network**.
3. For the Private Endpoint you want to delete, click the *...* (Actions) icon.
4. Click **Delete**.
5. Enter the endpoint name.
6. Click **Delete Endpoint**.
# Configure SSO with Okta
Source: https://docs.pinecone.io/guides/production/configure-single-sign-on/okta
Set up SAML single sign-on between Pinecone and Okta so your organization members can log in with corporate credentials.
This page describes how to set up Pinecone with Okta as the single sign-on (SSO) provider. These instructions can be adapted for any provider with SAML 2.0 support.
SSO is available on Standard and Enterprise plans.
## Before you begin
This page assumes you have the following:
* Access to your organization's [Pinecone console](https://login.pinecone.io) as an [organization owner](/guides/organizations/understanding-organizations#organization-roles).
* Access to your organization's [Okta Admin console](https://login.okta.com/).
## 1. Start SSO setup in Pinecone
First, start setting up SSO in Pinecone. In this step, you'll capture a couple values necessary for configuring Okta in [Step 2](#2-create-an-app-integration-in-okta).
1. In the Pinecone console, go to [**Settings > Access > Identity provider**](https://app.pinecone.io/organizations/-/settings/access/identity-provider).
2. In the **Single sign-on** section, click **Enable SSO**.
3. In the **Setup SSO** dialog, copy the **Entity ID** and the **Assertion Consumer Service (ACS) URL**. You'll need these values in [Step 2](#2-create-an-app-integration-in-okta).
4. Click **Next**.
Keep this window or browser tab open. You'll come back to it in [Step 4](#4-complete-sso-setup-in-pinecone).
## 2. Create an app integration in Okta
In [Okta](https://login.okta.com/), follow these steps to create and configure a Pinecone app integration:
1. If you're not already on the Okta Admin console, navigate there by clicking the **Admin** button.
2. Navigate to **Applications > Applications**.
3. Click **Create App Integration**.
4. Select **SAML 2.0**.
5. Click **Next**.
6. Enter the **General Settings**:
* **App name**: `Pinecone`
* **App logo**: (optional)
* **App visibility**: Set according to your organization's needs.
7. Click **Next**.
8. For **SAML Settings**, enter values you copied in [Step 1](#1-start-sso-setup-in-pinecone):
* **Single sign-on URL**: Your **Assertion Consumer Service (ACS) URL**
* **Audience URI (SP Entity ID)**: Your **Entity ID**
* **Name ID format**: `EmailAddress`
* **Application username**: `Okta username`
* **Update application username on**: `Create and update`
9. In the **Attribute Statements (SAML)** section, create the following attribute:
* **Name**: `email`
* **Value**: `user.email`
In newer versions of Okta, attribute statements are configured on the app's **Sign On** tab after the app is created, rather than in the app creation wizard. If you don't see the **Attribute Statements (SAML)** section here, finish creating the app, then add the attribute from **Applications > Pinecone > Sign On**, expanding **Show legacy configuration** if needed.
10. Click **Next**.
11. Click **Finish**.
## 3. Get the sign on URL and certificate from Okta
Next, in Okta, get the URL and certificate for the Pinecone application you just created. You'll use these in [Step 4](#4-complete-sso-setup-in-pinecone).
1. In the Okta Admin console, navigate to **Applications > Pinecone > Sign On**. If you're continuing from the previous step, you should already be on the right page.
2. In the **SAML 2.0** section, expand **More details**.
3. Copy the **Sign on URL**.
4. Download the **Signing Certificate**.
Download the certificate, don't copy it. The downloaded version contains necessary `-----BEGIN CERTIFICATE-----` and `-----END CERTIFICATE-----` lines.
## 4. Complete SSO setup in Pinecone
In the browser tab or window you kept open in [Step 1](#1-start-sso-setup-in-pinecone), complete the SSO setup in Pinecone:
1. In the **SSO Setup** window, enter the following values:
* **Login URL**: The URL copied in [Step 3](#3-get-the-sign-on-url-and-certificate-from-okta).
* **Email domain**: Your company's email domain. To target multiple domains, enter each domain separated by a comma.
* **Certificate**: The contents of the certificate file you copied in [Step 3](#3-get-the-sign-on-url-and-certificate-from-okta).
When pasting the certificate, be sure to include the `-----BEGIN CERTIFICATE-----` and `-----END CERTIFICATE-----` lines.
2. Choose whether or not to **Enforce SSO for all users**.
* If enabled, all members of your organization must use SSO to log in to Pinecone.
* If disabled, members can choose to log in with SSO or with their Pinecone credentials.
3. Click **Next**.
4. Select a **Default role** for all users who log in with SSO. You can change user roles later.
The **Default role** does not apply if you enable [SAML role management](/guides/production/configure-single-sign-on/okta-role-management). In that mode, every user's organization and project roles come entirely from your identity provider's SAML attributes.
When users first log in via SSO, they receive the default SSO role regardless of their previous role. Subsequent SSO logins do not change the role. If the default is **Member** or **Manager**, existing owners will lose owner access on their first SSO login.
To prevent losing access to organization management features:
* **Sole owner**: Temporarily set the default to **Owner**, log in via SSO to retain owner access, then change the default back to **Member**. After changing it back, check your organization's user list to verify no one else logged in via SSO while the default was **Owner**—if they did, adjust their roles accordingly.
* **Multiple owners**: Keep at least one owner signed in via email while others log in via SSO. That owner can restore roles as needed, then log in via SSO last.
If all owners lose access, [contact Support](https://app.pinecone.io/organizations/-/settings/support/ticket).
Okta is now ready to be used for single sign-on. Follow the [Okta docs](https://help.okta.com/en-us/content/topics/users-groups-profiles/usgp-main.htm) to learn how to add users and groups.
## Manage roles automatically
Optionally, you can have Pinecone assign organization and project roles automatically from your identity provider on each login, instead of managing them manually. For more information, see [Manage roles with Okta](/guides/production/configure-single-sign-on/okta-role-management).
# Manage roles with Okta
Source: https://docs.pinecone.io/guides/production/configure-single-sign-on/okta-role-management
Automatically assign Pinecone organization and project roles from SAML attributes with Okta.
Instead of managing roles manually in Pinecone, you can have Pinecone automatically assign organization and project roles from your identity provider (IdP) on each login. This page continues [Configure SSO with Okta](/guides/production/configure-single-sign-on/okta) and shows how to set up SAML role management with Okta. These instructions can be adapted for any provider with SAML 2.0 support.
SAML role management is available on the Enterprise plan and builds on SAML SSO. Before you begin, [configure SSO with Okta](/guides/production/configure-single-sign-on/okta) and enforce SSO for your organization.
## How it works
When SAML role management is enabled, Pinecone reconciles each user's roles on every SSO login:
* Pinecone reads the roles your IdP sends in the SAML `roles` attribute.
* It replaces the user's organization and project roles with *exactly* the roles in that attribute. Roles for projects not included in the attribute are removed, and values that don't match a known role are ignored.
* Because roles come entirely from your IdP, while this mode is enabled you can no longer invite members or edit roles in the Pinecone console or through the Admin API, and the SSO **Default role** is not applied.
* To revoke a member's access, remove their roles in your IdP. At their next sign-in, Pinecone clears all of their organization and project roles and blocks the login. Active members are re-authenticated at least every 24 hours, so the change applies within a day.
Because SSO is enforced, deactivating or removing a member in your IdP blocks them from signing in to Pinecone right away, so their access ends immediately. Their role assignments stay in Pinecone until their next sign-in—which a removed member never reaches—so the assignments remain but grant no access on their own. To clear them, or to have Pinecone remove members automatically, use [SCIM provisioning](/guides/production/configure-single-sign-on/okta-scim-provisioning). You can also switch to **Manage roles in Pinecone** to remove the member manually, then switch back.
To avoid losing access, configure and verify the `roles` attribute in Okta *before* you enable SAML role management in Pinecone. The steps below are in that order.
Enabling SAML role management does not validate your IdP configuration, so a user missing an organization role can be locked out on their next login. Before you enable it, verify the `roles` attribute for a current owner (see [Step 2](#2-verify-the-roles-in-the-saml-assertion)).
## Role attribute values
Pinecone reads roles from the `roles` attribute. Each value uses one of the following formats:
* Organization role: `pinecone:`
* Project role: `pinecone:project::`
`` is the project's unique ID. To find it, go to the project list in the [Pinecone console](https://app.pinecone.io/organizations/-/projects). For more information, see [Project IDs](/guides/projects/understanding-projects#project-ids).
A user can hold multiple roles by sending multiple values in the `roles` attribute.
### Organization roles
For details on what each [organization role](/guides/organizations/understanding-organizations#organization-roles) grants, see [Understanding organizations](/guides/organizations/understanding-organizations#organization-roles).
| Organization role | Attribute value |
| :------------------- | :------------------------- |
| Organization owner | `pinecone:OrgOwner` |
| Organization manager | `pinecone:OrgManager` |
| Organization member | `pinecone:OrgMember` |
| Billing admin | `pinecone:OrgBillingAdmin` |
### Project roles
For details on what each [project role](/guides/projects/understanding-projects#project-roles) grants, see [Understanding projects](/guides/projects/understanding-projects#project-roles).
| Project role | Attribute value |
| :------------------- | :------------------------------------------------ |
| Project owner | `pinecone:project::ProjectOwner` |
| Project manager | `pinecone:project::ProjectManager` |
| Project member | `pinecone:project::ProjectMember` |
| Control plane editor | `pinecone:project::ControlPlaneEditor` |
| Control plane viewer | `pinecone:project::ControlPlaneViewer` |
| Data plane editor | `pinecone:project::DataPlaneEditor` |
| Data plane viewer | `pinecone:project::DataPlaneViewer` |
For example, to make a user an organization manager who is also a project owner on one project, send these two values in the `roles` attribute:
```text theme={null}
pinecone:OrgManager
pinecone:project:a2f7dddb-1597-4eff-9f71-535fde243f58:ProjectOwner
```
## 1. Send roles from Okta
Configure Okta to send each user's roles in a SAML attribute named `roles`, where each value is one of the [role attribute values](#role-attribute-values) above. You can populate that attribute in a few ways; choose whichever fits how you already manage users in Okta.
In newer versions of Okta, attribute and group statements are configured on the app's **Sign On** tab after the app is created, rather than in the app creation wizard. If you don't see the **Attribute Statements (SAML)** section, expand **Show legacy configuration** within it.
### Option A: From a user profile attribute
Use this option to set roles directly on each user's Okta profile.
1. In Okta, go to **Directory > Profile Editor** and edit the **Okta** user profile.
2. Add an attribute named `pineconeRoles` with data type **string array**.
3. For each user, set `pineconeRoles` to their `pinecone:*` values (directly, or through a profile mapping).
4. In **Applications > Pinecone > Sign On**, add an **Attribute Statement**:
* **Name**: `roles`
* **Name format**: `Unspecified`
* **Value**: `user.pineconeRoles`
### Option B: From group membership
Use this option to assign roles by adding users to Okta groups.
1. In Okta, create a group for each Pinecone role you want to assign, naming each group exactly as the role's attribute value (for example, `pinecone:OrgOwner` or `pinecone:project::ProjectManager`), and add the appropriate users to each group.
2. In **Applications > Pinecone > Sign On**, send those group names in the `roles` attribute using either:
* A **Group Attribute Statement** with **Name** `roles`, **Name format** `Unspecified`, and **Filter** **Starts with** `pinecone:`.
* Or an **Attribute Statement** with **Name** `roles` and the expression `user.getGroups({'group.profile.name': 'pinecone:', 'operator': 'STARTS_WITH'}).![profile.name]`.
The `user.getGroups(...).![profile.name]` expression is for an app-level attribute statement on the **Sign On** tab, and it returns every matching group, so no `limit` argument is required. (Only the `Groups.startsWith`, `Groups.endsWith`, and `Groups.contains` functions require a `limit`.) If you configure this claim on a custom authorization server instead, use the `.![name]` projection.
Any other approach works as well, as long as the `roles` attribute resolves to the role attribute values.
## 2. Verify the roles in the SAML assertion
Before you hand role management to Okta, confirm the `roles` attribute contains what you expect.
1. In **Applications > Pinecone > Sign On**, click **Preview the SAML Assertion**.
2. Select a user who should be an organization owner and generate the preview.
3. Confirm the assertion includes a `roles` attribute containing `pinecone:OrgOwner` (and any project roles you assigned).
If no current organization owner's preview includes `pinecone:OrgOwner`, fix your Okta configuration before continuing. Enabling SAML role management without a provisioned owner can lock your organization out of role management. If the `roles` attribute is empty or missing, re-check your attribute statement expression and projection before continuing, as a malformed expression returns no roles rather than an error.
## 3. Enable SAML role management in Pinecone
You must be an [organization owner](/guides/organizations/understanding-organizations#organization-roles) on the Enterprise plan, and SSO must be enforced for your organization.
1. In the Pinecone console, go to [**Settings > Access > Identity provider**](https://app.pinecone.io/organizations/-/settings/access/identity-provider).
2. Confirm that single sign-on shows the **Enforced** status. If it does not, edit your SSO configuration to enforce SSO before continuing.
3. In the **User management** section, select **Manage roles with SAML attributes**.
4. In the **Enable SAML role management** dialog, review the **Before you enable** prerequisites, then click **Enable SAML role management**.
Role assignment now comes entirely from your IdP. Roles update at the member's next SSO login. Since SAML sessions re-authenticate at least every 24 hours, an active user's role changes apply within 24 hours. Default role assignments configured during SSO setup no longer apply.
To stop syncing roles from your IdP, return to **Settings > Access > Identity provider** and select **Manage roles in Pinecone**. Existing roles are preserved, and you can edit them again in the console.
# SCIM provisioning with Okta
Source: https://docs.pinecone.io/guides/production/configure-single-sign-on/okta-scim-provisioning
Automatically provision members and roles from Okta to Pinecone over SCIM.
Instead of managing members and roles manually in Pinecone, you can have your identity provider (IdP) provision them automatically over SCIM. This page continues [Configure SSO with Okta](/guides/production/configure-single-sign-on/okta) and shows how to set up SCIM provisioning with Okta. These instructions can be adapted for any provider with SCIM 2.0 support.
SCIM provisioning is available on the Enterprise plan and builds on SAML SSO. Before you begin, [configure SSO with Okta](/guides/production/configure-single-sign-on/okta) and enforce SSO for your organization.
## How it works
When SCIM provisioning is enabled, your IdP manages organization membership and roles in Pinecone in near real time:
* As members are added, updated, or removed in Okta, those changes sync to Pinecone over SCIM in near real time, not just at login.
* Okta connects to a SCIM endpoint that Pinecone provides, authenticating with a bearer token you generate in the Pinecone console.
* Pinecone reads each member's roles from the SCIM `roles` attribute and sets their organization and project roles to *exactly* those values. Values that don't match a known role are ignored.
* While SCIM is enabled, SCIM is the source of truth for roles: Pinecone no longer applies the roles in a member's SAML login assertion, even though members still sign in through SAML SSO.
* Deactivating or removing a member in Okta removes them from the organization, and clearing a member's roles revokes their access.
* Because membership and roles come entirely from your IdP, while SCIM is enabled you can no longer invite members or edit roles in the Pinecone console or through the Admin API.
Provisioning changes in Okta are typically reflected in Pinecone within a few minutes, but can take up to 30 minutes to fully propagate.
SCIM provisioning assigns roles from user attributes only. SCIM group push is not supported. This is similar to [SAML role management](/guides/production/configure-single-sign-on/okta-role-management), except roles are provisioned continuously rather than at each login, and member deprovisioning is handled automatically.
Before you enable SCIM, provision at least one current [organization owner](/guides/organizations/understanding-organizations#organization-roles) with the `pinecone:OrgOwner` role. Pinecone blocks enabling SCIM until a current owner has been provisioned as an owner, so that handing role management to your IdP cannot lock you out.
SCIM provisioning is not compatible with members who belong to more than one SSO-connected Pinecone organization. If a member is part of multiple SSO-connected organizations, do not provision them through SCIM; manage their roles manually instead.
## Role attribute values
Pinecone reads roles from the `roles` attribute. Each value uses one of the following formats:
* Organization role: `pinecone:`
* Project role: `pinecone:project::`
`` is the project's unique ID. To find it, go to the project list in the [Pinecone console](https://app.pinecone.io/organizations/-/projects). For more information, see [Project IDs](/guides/projects/understanding-projects#project-ids).
A user can hold multiple roles by sending multiple values in the `roles` attribute.
### Organization roles
For details on what each [organization role](/guides/organizations/understanding-organizations#organization-roles) grants, see [Understanding organizations](/guides/organizations/understanding-organizations#organization-roles).
| Organization role | Attribute value |
| :------------------- | :------------------------- |
| Organization owner | `pinecone:OrgOwner` |
| Organization manager | `pinecone:OrgManager` |
| Organization member | `pinecone:OrgMember` |
| Billing admin | `pinecone:OrgBillingAdmin` |
### Project roles
For details on what each [project role](/guides/projects/understanding-projects#project-roles) grants, see [Understanding projects](/guides/projects/understanding-projects#project-roles).
| Project role | Attribute value |
| :------------------- | :------------------------------------------------ |
| Project owner | `pinecone:project::ProjectOwner` |
| Project manager | `pinecone:project::ProjectManager` |
| Project member | `pinecone:project::ProjectMember` |
| Control plane editor | `pinecone:project::ControlPlaneEditor` |
| Control plane viewer | `pinecone:project::ControlPlaneViewer` |
| Data plane editor | `pinecone:project::DataPlaneEditor` |
| Data plane viewer | `pinecone:project::DataPlaneViewer` |
For example, to make a user an organization manager who is also a project owner on one project, send these two values in the `roles` attribute:
```text theme={null}
pinecone:OrgManager
pinecone:project:a2f7dddb-1597-4eff-9f71-535fde243f58:ProjectOwner
```
## 1. Start SCIM setup in Pinecone
You must be an [organization owner](/guides/organizations/understanding-organizations#organization-roles) on the Enterprise plan, and SSO must be enforced for your organization.
1. In the Pinecone console, go to [**Settings > Access > Identity provider**](https://app.pinecone.io/organizations/-/settings/access/identity-provider).
2. Confirm that single sign-on shows the **Enforced** status. If it does not, edit your SSO configuration to enforce SSO before continuing.
3. In the **User management** section, select **Manage roles with SCIM provisioning**.
4. In the **Set up SCIM provisioning** dialog, review the instructions and click **Get started**.
## 2. Generate a SCIM token
1. Choose the token's permissions and expiry. By default the token grants all user permissions and expires in 90 days; you can also choose **Token never expires**.
2. Click **Generate token**.
3. Copy the **bearer token**. The **SCIM endpoint** is shown on the next screen of the dialog. You'll add both to Okta in [Step 3](#3-connect-okta-to-the-scim-endpoint).
The bearer token is shown only once. Copy it before closing the dialog. You can have at most two active tokens per organization; rotate or revoke them later from the **Manage** dialog.
## 3. Connect Okta to the SCIM endpoint
1. In [Okta](https://login.okta.com/), navigate to **Applications > Pinecone > General**.
2. In the **App Settings** section, click **Edit**, set **Provisioning** to **SCIM**, and click **Save**.
3. Open the **Provisioning** tab and click **Configure API Integration**.
4. Select **Enable API Integration** and enter the following:
* **SCIM connector base URL**: The **SCIM endpoint** you copied in [Step 2](#2-generate-a-scim-token).
* **Unique identifier field for users**: `userName`.
* **Authentication Mode**: `HTTP Header`.
* **Authorization**: The **bearer token** you copied in [Step 2](#2-generate-a-scim-token).
5. Click **Test API Credentials** to verify the connection, then click **Save**.
6. Under **Provisioning > To App**, click **Edit** and enable **Create Users**, **Update User Attributes**, and **Deactivate Users**.
If the **Provisioning** tab or **Configure API Integration** button does not appear, SCIM provisioning is not enabled on the app.
If **Test API Credentials** fails, re-copy the SCIM endpoint and bearer token from Pinecone, and confirm the token has not expired or been revoked.
## 4. Send role values to Pinecone
Okta does not send a member's Pinecone roles by default. You define one app attribute per role you want to assign, then map a value to it for the right members. Pinecone reads only each value, so the same approach scales to as many roles as you need.
1. In Okta, go to **Directory > Profile Editor** and open the **Pinecone** app profile.
2. For each role you want to assign, click **Add Attribute** and configure:
* **Data type**: `string`
* **External name**: `roles.^[type=='