pgvector extension. Once state is external, every replica is stateless and interchangeable, and you can scale horizontally. Postgres is the only external dependency, there is no separate vector database or object storage to run.
If you already run Milvus or Zilliz Cloud, you can send vectors there instead of pgvector. See Vector stores for all the options; this page uses the default pgvector setup throughout.
You only need this if a single container can no longer handle your query or indexing load. Most deployments run fine on one container with a persistent volume. See Docker and Kubernetes for the standard single-container setup.
Architecture
Every replica runs the full application (REST API, MCP endpoint, and parser) and is interchangeable. All shared state lives in PostgreSQL, so a load balancer can spread traffic across any number of replicas. Replicas coordinate through Postgres: they pull indexing jobs from a shared queue, run jobs that must happen once (backups, usage reporting, GitOps sync) on a single replica using a Postgres lock, and validate each other’s signed session tokens. See How it behaves for the details.What you need
- A PostgreSQL database (managed or self-hosted) with the pgvector extension, reachable from every replica. Managed Postgres such as RDS, Cloud SQL, and Azure support pgvector; for self-hosted use the
pgvector/pgvectorimage. To keep vectors in Milvus or Zilliz Cloud instead, see Vector stores. - A load balancer in front of the replicas.
DATABASE_URL is set.
Configuration
Set the same values on every replica. Presence ofDATABASE_URL is what switches the store from SQLite to Postgres and vectors to pgvector.
Enable it
1
Provision PostgreSQL with pgvector
Context7 stores vectors with pgvector. You need PostgreSQL 13 or newer with pgvector 0.5.0 or newer (0.5.0 added the HNSW index used for similarity search).On first boot Context7 runs Verify the installed version (must be
CREATE EXTENSION IF NOT EXISTS vector and creates its tables and indexes automatically. You just provide a database whose user is allowed to create the extension. On managed Postgres that usually means enabling pgvector for the instance first, then connecting with a privileged role.- AWS RDS / Aurora
- Google Cloud SQL
- Azure Flexible Server
- Self-hosted / Docker
pgvector ships with RDS and Aurora PostgreSQL. Connect as the master user (or a member of No parameter group changes are required. See pgvector on Amazon RDS.
rds_superuser) and enable it:0.5.0 or newer):If the application’s database user cannot run
CREATE EXTENSION (common on locked-down managed instances), have a DBA run it once as a privileged role before you start Context7. Once the extension exists, the app user only needs normal table privileges.2
Generate the shared secrets
3
Set the environment on every replica
Add
DATABASE_URL and ENCRYPTION_KEY to each replica, alongside the usual LICENSE_KEY and model settings.4
Point health checks at /api/ready
Configure your load balancer or orchestrator readiness check to use
GET /api/ready. It returns 200 only when the replica can reach the database and its MCP bridge is up, so traffic is routed only to replicas that are ready.5
Scale out
Start as many replicas as you need behind the load balancer. Every replica is identical: it serves API, MCP, and search traffic and pulls parse jobs from the shared queue, so adding replicas grows both query capacity and indexing throughput at once. Work is distributed automatically and no replica is special.If a large re-index competes with query latency on a replica, lower Max concurrent parses (Settings > Indexing) so each replica runs fewer parses at a time, or give replicas more CPU and memory.
Docker Compose
For evaluation and small deployments, this stack brings up Postgres (with pgvector), three app replicas, and an nginx load balancer with one command. There is no object storage to run. Create a.env:
nginx.conf (round-robins across the replicas):
docker-compose.yml:
http://localhost:3000 to complete the setup wizard:
DATABASE_URL at an external managed Postgres (with pgvector) and drop the postgres service.
Kubernetes
This assumes you created the namespace and image pull secret in the Kubernetes guide. Put the shared configuration in a Secret:secret.yaml
Deployment instead of the single-replica StatefulSet. State is external, so /data is per-pod scratch and readiness gates on /api/ready:
deployment.yaml
Service and Ingress from the Kubernetes guide, then apply:
A Helm chart renders all of this from a few values (single replica by default,
scaling.enabled=true to scale out) and ships with the enterprise distribution.How it behaves
- Shared work queue. All replicas pull parse jobs from the same queue in PostgreSQL, so indexing throughput scales with replica count.
- Single execution for scheduled jobs. Jobs that must run once across the fleet, such as the usage report, scheduled backups, and GitOps sync, take a short Postgres advisory lock when they fire, so exactly one replica runs each. No replica is special, and there is nothing to fail over.
- Stateless sessions. Sessions are signed tokens, so any replica accepts a login issued by another, and logins survive restarts.
- Vectors in Postgres. Embeddings are stored with pgvector, indexed with HNSW using cosine distance. The vector dimension is taken from your embedding model on first write, so there is no manual schema setup and switching embedding models is a re-index, not a migration. To store vectors in Milvus or Zilliz Cloud instead, see Vector stores.
Migrating an existing deployment
If you already run a single container, a built-in command copies your existing SQLite data and LanceDB vectors into PostgreSQL, so you do not have to re-index your libraries or re-embed anything. It reads the data directory from your single container and writes to the target PostgreSQL. The admin UI shows your current storage mode and the exact migration command under Settings > Scaling:
1
Provision PostgreSQL with pgvector
Create the target PostgreSQL database with pgvector, the same way as in Enable it above. The schema, extension, and vector tables are created automatically.
2
Run the migration
Run the one-shot Use the same volume (The command prints the rows and vectors copied, and the
migrate command with access to your existing data directory and the target database. It creates the schema and copies your projects, pages, users, API keys, per-library access rules, SSO group memberships, settings, usage counters, and the vector index into pgvector.- Docker
- Kubernetes
context7-data) your single container uses, so the command reads your existing database and vectors.ENCRYPTION_KEY your new deployment must use.3
Reuse the encryption key
Your stored credentials are encrypted with the key from the single container. Set
ENCRYPTION_KEY on the new deployment to the value the migration command printed, so credentials stay readable.4
Redeploy in multi-replica mode
Redeploy with
DATABASE_URL and ENCRYPTION_KEY set on every replica, following the steps above. Verify at /api/health that your libraries are present, then scale up.
Limitations
- With pgvector, vector search runs in Postgres. For typical on-prem workloads this is well within reach; for a very large index, size Postgres accordingly.
- Database backups are handled by PostgreSQL in this mode. Use your provider’s managed backups or
pg_dumprather than the built-in backup, which targets the embedded SQLite file. See Backup and Restore.