Licensing in 2026

CockroachDB Core moved to BSL in late 2024 (similar to HashiCorp's move). For internal use, BSL CockroachDB is free; for hosted-service redistribution, the license requires a paid agreement. The fork to watch is OpenSpyce / community-led; for most teams running CockroachDB internally, BSL is fine.

Install for a local 3-node cluster

CR_VER=v24.3.1
curl -L "https://binaries.cockroachdb.com/cockroach-${CR_VER}.linux-amd64.tgz" \
    | tar -xz
sudo cp cockroach-${CR_VER}.linux-amd64/cockroach /usr/local/bin/

cockroach version

Three nodes, one machine (for testing)

mkdir -p ~/crdb/node{1,2,3}

# Generate CA + node certs for an insecure-development cluster, or use --insecure
# (only for local testing; never insecure mode on a network).
cockroach cert create-ca \
    --certs-dir=~/crdb/certs --ca-key=~/crdb/ca.key

for n in 1 2 3; do
    cockroach cert create-node localhost 127.0.0.1 \
        --certs-dir=~/crdb/certs --ca-key=~/crdb/ca.key
done

cockroach cert create-client root --certs-dir=~/crdb/certs --ca-key=~/crdb/ca.key

# Start three nodes on different ports
cockroach start --insecure --store=node1 --listen-addr=127.0.0.1:26257 \
    --http-addr=127.0.0.1:8080 --join=127.0.0.1:26257,127.0.0.1:26258,127.0.0.1:26259 \
    --background

cockroach start --insecure --store=node2 --listen-addr=127.0.0.1:26258 \
    --http-addr=127.0.0.1:8081 --join=127.0.0.1:26257,127.0.0.1:26258,127.0.0.1:26259 \
    --background

cockroach start --insecure --store=node3 --listen-addr=127.0.0.1:26259 \
    --http-addr=127.0.0.1:8082 --join=127.0.0.1:26257,127.0.0.1:26258,127.0.0.1:26259 \
    --background

# Bootstrap the cluster (run once across the joined nodes)
cockroach init --insecure --host=127.0.0.1:26257

Three nodes running locally; admin UI at http://localhost:8080.

Production: 3+ nodes across availability zones

For real durability, run one node per AZ in a region (3-node minimum for fault tolerance, 5 nodes for tolerating 2 simultaneous failures). Each node:

cockroach start \
    --certs-dir=/etc/cockroach/certs \
    --store=path=/var/lib/cockroach,attrs=ssd \
    --listen-addr=:26257 \
    --http-addr=:8080 \
    --advertise-addr=node1.lab.example.com:26257 \
    --join=node1.lab.example.com:26257,node2.lab.example.com:26257,node3.lab.example.com:26257 \
    --locality=region=us-east,zone=us-east-1a \
    --cache=.25 --max-sql-memory=.25

--locality tags are critical — CockroachDB uses them to spread replicas across failure domains and to make region-aware routing decisions.

Connect with psql (or any Postgres client)

cockroach sql --insecure --host=localhost:26257
# Or with TLS:
cockroach sql --certs-dir=/etc/cockroach/certs --host=node1.lab.example.com:26257

# Or with stock psql against the Postgres-wire endpoint
psql -h node1.lab.example.com -p 26257 -U root postgres

From any application, treat it as Postgres:

DATABASE_URL=postgresql://root@node1.lab.example.com:26257/myapp?sslmode=verify-full&sslrootcert=/etc/cockroach/certs/ca.crt

Schema + transactions

CREATE DATABASE myapp;
USE myapp;

CREATE TABLE users (
    id   UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    email STRING NOT NULL UNIQUE,
    name  STRING,
    created TIMESTAMPTZ DEFAULT now()
);

CREATE TABLE posts (
    id      UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID NOT NULL REFERENCES users(id),
    title   STRING NOT NULL,
    body    STRING,
    INDEX   (user_id, created)
);

-- Transactions work like Postgres
BEGIN;
INSERT INTO users (email, name) VALUES ('alice@example.com', 'Alice');
INSERT INTO posts (user_id, title, body) VALUES
    ((SELECT id FROM users WHERE email='alice@example.com'),
     'First post', 'Hello world');
COMMIT;

CockroachDB's isolation defaults to SERIALIZABLE (Postgres defaults to READ COMMITTED). Stricter than what most apps actually need, but the guarantee is stronger; expect more retries on contended writes (Cockroach surfaces a 40001 serialization-failure error which the client retries).

The big differences from Postgres

  • Schema changes are online and asynchronous. ALTER TABLE ADD COLUMN doesn't lock; the column is rolled out cluster-wide in the background. Status visible via SHOW JOBS.
  • No materialized views. Use a regular VIEW + caching layer, or schedule a recurring INSERT...SELECT into a real table.
  • Triggers are limited. Basic BEFORE INSERT / UPDATE triggers are supported in 24.x; complex Postgres trigger workloads need restructuring.
  • Stored procedures & PL/pgSQL — gaining support, but historically a non-feature. Logic lives in the application.
  • Per-row primary keys are 64-bit hash of the actual key — range queries on monotonic primary keys (e.g. id SERIAL) create hotspots; use UUIDs or hash partitioning instead. Cockroach's gen_random_uuid() default is the canonical choice.
  • EXPLAIN ANALYZE returns distributed-execution plans — takes practice to read vs Postgres's familiar single-node trees.

Multi-region survivability

The killer feature. With nodes spread across regions:

-- Pin a database's replicas across regions
ALTER DATABASE myapp PRIMARY REGION 'us-east-1';
ALTER DATABASE myapp ADD REGION 'us-west-2';
ALTER DATABASE myapp ADD REGION 'eu-central-1';

-- Per-table policies: where do replicas live?
ALTER TABLE users SET LOCALITY GLOBAL;             -- replicas everywhere; high read availability
ALTER TABLE posts SET LOCALITY REGIONAL BY ROW;    -- per-row pinning to a region
ALTER TABLE sessions SET LOCALITY REGIONAL BY TABLE IN 'us-east-1';

Lose a whole region: surviving regions still serve reads + writes for non-pinned tables; pinned tables lose availability for that region's data only. No "promote a replica" or "fail over"; the cluster keeps running.

Backups

-- Manual backup to S3
BACKUP DATABASE myapp INTO 's3://my-bucket/cockroach-backups?AWS_ACCESS_KEY_ID=...&AWS_SECRET_ACCESS_KEY=...';

-- Scheduled (Enterprise feature in BSL; OSS users use cron + above)
CREATE SCHEDULE my_backup_schedule
    FOR BACKUP INTO 's3://my-bucket/cockroach-backups'
    RECURRING '@daily'
    WITH SCHEDULE OPTIONS first_run = 'now';

-- Restore
RESTORE DATABASE myapp FROM LATEST IN 's3://my-bucket/cockroach-backups';

When CockroachDB is the right tool

  • Workloads that have outgrown one Postgres node and the team prefers continued SQL semantics over sharding.
  • Multi-region active-active where eventual-consistency systems like DynamoDB Global Tables aren't an option due to transaction needs.
  • Operational simplicity at scale — the cluster auto-rebalances, repairs failed nodes, handles version upgrades node-by-node without downtime.

When it's wrong

  • For a single-node workload that fits comfortably on Postgres, CockroachDB's per-query overhead (network round-trips between SQL and KV layer) is noticeable; plain Postgres is faster.
  • For analytics / OLAP, the row-oriented design is the wrong shape; use ClickHouse (see that tutorial) or DuckDB (see that tutorial).
  • For apps that depend heavily on Postgres extensions (PostGIS, pgvector, hstore) — CockroachDB has spatial support and a vector extension as of 24.x, but the ecosystem is much narrower than Postgres's.

Alternatives in the same space

  • TiDB — PingCAP's distributed SQL; MySQL-protocol-compatible instead of Postgres. Different SQL dialect; similar architectural pitch.
  • YugabyteDB — another distributed SQL; Postgres-protocol-compatible; the YSQL layer reuses Postgres's parser/planner so dialect compatibility is closer.
  • Neon / Aurora / AlloyDB — managed Postgres with separated compute/storage; horizontal-read scaling but single-writer.