Skip to main content
CockroachDB is a distributed SQL database built on a transactional and strongly-consistent key-value store. It scales horizontally, survives disk, machine, rack, and even datacenter failures with minimal latency disruption and no manual intervention.
Key features:
  • Distributed SQL: Scale out while maintaining ACID guarantees
  • Native vector support: Built-in VECTOR type (v24.2+) and C-SPANN indexes (v25.2+)
  • PostgreSQL compatible: Drop-in replacement for PostgreSQL applications
  • Global replication: Multi-region deployments with low latency
  • Automatic sharding: Data automatically distributed across nodes
  • SERIALIZABLE isolation: Strongest isolation level by default

Installation and Setup

Install the LangChain integration:
Requires CockroachDB v25.4 or later.

Get your CockroachDB connection string

You’ll need a CockroachDB cluster. Choose one option: Option 1: CockroachDB Cloud (Recommended)
  1. Sign up at cockroachlabs.cloud
  2. Create a free cluster
  3. Get your connection string: cockroachdb://user:pass@host:26257/db?sslmode=verify-full
Option 2: Docker (Development)
Connection string: cockroachdb://root@localhost:26257/defaultdb?sslmode=disable Option 3: Local Binary Download from cockroachlabs.com/docs/releases

Integrations

Vector Store

CockroachDB can be used as a vector store with native VECTOR type and C-SPANN distributed indexes. Key features:
  • Native vector support (v24.2+)
  • C-SPANN indexes optimized for distributed systems (v25.2+)
  • Advanced metadata filtering
  • Hybrid search combining full-text and vector similarity (v0.3.0+)
  • Multi-tenancy with prefix columns
  • Horizontal scalability
See the CockroachDB entry in the vector stores overview for links to detailed usage. Quick example:
Hybrid search (v0.3.0+) runs full-text and vector search in parallel and fuses the ranked results, using reciprocal rank fusion by default:

Chat Message History

Store conversation history in CockroachDB for persistent, distributed chat applications. Key features:
  • Distributed storage with automatic replication
  • Strong consistency (SERIALIZABLE)
  • Session-based organization
  • High availability
See CockroachDB chat history documentation for detailed usage. Quick example:
Sharing an engine reuses its connection pool and retry policy.

LangGraph Checkpointer

Persist LangGraph workflow state in CockroachDB for short-term memory, human-in-the-loop interactions, and fault tolerance. Both sync (CockroachDBSaver) and async (AsyncCockroachDBSaver) implementations are available.
Call checkpointer.setup() (or await checkpointer.setup()) the first time you use the CockroachDB checkpointer to create the required tables.
See Get your CockroachDB connection string above for connection options including CockroachDB Cloud (recommended for production), Docker, and local binary installs. For local development, sslmode=disable is acceptable; always use sslmode=verify-full in production.
The checkpointer uses raw psycopg3 connections (not SQLAlchemy) for compatibility with LangGraph’s checkpoint interface. The from_conn_string factory accepts cockroachdb:// URLs and converts them automatically.

Row-Level TTL (v0.2.1+)

Automatically expire old checkpoint data using CockroachDB’s Row-Level TTL:
From v0.6.0, an active thread keeps the values it still uses, even when they are older than the interval, and a thread expires as a whole once it has been idle for the interval. When the setting changes, enable_ttl() pauses TTL, waits about 15 seconds, and brings existing threads up to date before it resumes TTL, so run it once after upgrading, from a single process. Later calls with the same setting return at once. Async variant: await checkpointer.aenable_ttl(ttl_interval="7 days", cron="@hourly")
TTL deletion is eventual — expired rows remain queryable until CockroachDB’s background job runs on the specified cron schedule.

Performance optimizations (v0.2.1+)

The checkpointer includes several optimizations for low-latency reads:
  • Batch fetching: list() fetches all blobs and writes in 2 batch queries instead of 2 per checkpoint
  • Raw BYTEA: Uses psycopg3 binary protocol instead of hex-encoding blobs in SQL
  • Prepared statements: prepare_threshold defaults to 5 and can be changed in from_conn_string
  • Concurrent setup: setup() is safe to run from several processes at once
  • Connection pools (v0.4.1+): For long-running services, pass a psycopg_pool connection pool rather than a single connection. A saver on a pool runs operations concurrently, each on its own pooled connection, so one saver can serve many agents; set the pool’s max_size for the number of agents running at once. A saver on a single connection runs one operation at a time, and it cannot recover once that connection drops, which includes from_conn_string(..., pipeline=True)
  • Atomic writes (v0.4.1+): A checkpoint write with several statements goes to the database as one batch, so a write that is cancelled partway saves nothing. It still takes one round trip

LangGraph Store

Persist LangGraph long-term memory in CockroachDB: memories that outlive a conversation thread, such as user preferences and facts an agent learned. Both sync (CockroachDBStore) and async (AsyncCockroachDBStore) implementations are available. They require langchain-cockroachdb v0.5.0 or later and follow the API of PostgresStore, so they work with create_agent(store=...) and StateGraph.compile(store=...).
Call store.setup() (or await store.setup()) the first time you use the CockroachDB store to create the required tables.
Quick example:
Pass index to embed items when you put them and to rank searches by similarity to a query. With DB_URI as above:
setup() creates a C-SPANN vector index with the namespace as a prefix column, so a search under one user’s namespace reads only that part of the index. distance_type can be "cosine" (the default), "l2", or "inner_product".

Expire memories with TTL

Pass ttl to give items an expiry, in minutes. setup() then turns on CockroachDB’s row-level TTL job, which deletes expired items on the server, so no sweeper thread is needed:
Reads, searches, and listings leave out expired items until the job deletes them. A get or search pushes back the expiry of the items it returns, unless refresh_on_read is False. To turn the job off, call store.disable_ttl(), or await store.adisable_ttl() on AsyncCockroachDBStore.

Delete a namespace

delete_namespace deletes every item in a namespace and its descendants, with their vectors, in one transaction, and returns the number of items deleted:
On AsyncCockroachDBStore, use await store.adelete_namespace(...).

Keep memories true (v0.6.0+)

Semantic search ranks memories by similarity to a query, not by whether they are still true. reconcile writes a memory and settles the memories it may conflict with under a policy you choose, in one serializable transaction. The store makes no LLM calls.
On a store upgraded from v0.5, run setup() once before you use the methods in this section. It applies migration 2, which adds the columns they need, and until it runs they raise ValueError. Wait until every writer runs v0.6.0 before you turn history on.
A slot names the fact a memory states. With slot="topic", the candidates include the memory under the same key and every live memory in the namespace whose topic field holds the same value. first_of(skip_duplicates(), supersede_same_slot()) skips a repeat and confirms the memory it repeats, and otherwise lets a newer fact in the same slot supersede the old one. reconcile has no default policy. With DB_URI as above, these tools save a fact under a topic that the model names, and list what the user used to say about it:
With history=True, every write that overwrites, supersedes, or deletes a memory keeps the version it ends, with its provenance, when its fact was true, and why it ended. Plain put and delete keep history too. history(namespace, key) lists one memory’s old versions, newest first, and history(namespace) lists those of every memory in the namespace, which gives a timeline even for memories saved under generated keys. confirm(namespace, key) marks a memory as confirmed: it counts the confirmation and renews the memory’s expiry. With refresh_on_read set to False in the store’s ttl, expiry follows confirmations rather than reads. record(namespace, key) reads a memory with its version and provenance. put_if(namespace, key, value, expected=record) and delete_if(namespace, key, expected=record) apply only if the memory is still the one record returned, so two writers cannot lose an update. A conflict comes back in the result instead of as an exception: applied is False, and current holds the live memory to merge with. On a store with history, delete is a soft delete: the version it ends stays in history. purge(namespace, key) forgets one key: the memory, its vectors, and its history. A memory that reconcile superseded keeps its own key in history, so purge that key as well, or use delete_namespace to forget everything under a namespace, history included. On AsyncCockroachDBStore, each of these methods has an async form with an a prefix, such as await store.areconcile(...).

Multi-tenancy

Isolate vector data by tenant using an opt-in namespace column. When enabled, all CRUD and search operations are scoped to the specified namespace. CockroachDB’s C-SPANN indexes support prefix columns, so namespace filtering uses the vector index directly without a separate scan.
From v0.6.0, a search with a metadata filter also uses the C-SPANN index: the store applies the filter to the nearest rows from the index and runs an exact search only when too few rows pass. The namespace must be the index’s only prefix column, as in the example, and results that come from the index are approximate, like any index search. Document ids must be unique across namespaces. Ids the library generates always are, and adding a document whose id already belongs to another namespace raises ValueError without writing anything.

Retries and resilience (v0.4.0+)

Every operation retries transient CockroachDB errors: serialization failures (40001), ambiguous results (40003), connection errors (08xxx), node drains (57P01) and the CockroachDB range and node failures 58C00 and 58C01. All writes are idempotent, so a retry after an ambiguous result never duplicates data. Configure it once on the engine:
The vector store and chat history inherit the engine’s policy. The checkpointers accept retry_policy too; give them a psycopg_pool connection pool so dropped connections are replaced. Since v0.4.1, a pooled checkpointer also retries whenever psycopg reports its connection broken, which covers TLS connections that drop on CockroachDB Cloud.

Why CockroachDB for AI applications?

Distributed by design

  • Horizontal scalability: Add nodes to handle more load
  • Multi-region deployments: Serve users globally with low latency
  • Automatic rebalancing: Data distributes automatically across nodes

Production-ready reliability

  • High availability: Survives node, rack, and datacenter failures
  • Zero-downtime upgrades: Rolling updates without downtime
  • Backups and restores: Point-in-time recovery

Vector search at scale

  • C-SPANN indexes: Distributed approximate nearest neighbor search
  • Native vector type: First-class support for embeddings
  • Real-time indexing: No rebuild needed for new vectors
  • Multi-tenancy: Prefix columns for efficient tenant isolation

PostgreSQL compatibility

  • Easy migration: Drop-in replacement for PostgreSQL
  • Familiar SQL: Standard PostgreSQL syntax
  • Existing tools: Works with PostgreSQL drivers and tools

Resources

Support