New: kingres_shard 0.3 moves buckets between shard groups with logical replication. See what shipped
0.1.0 Pre-release · built on PostgreSQL 18.7

Distributed PostgreSQL with a ledger you can verify.

KingresDB is a thin fork of PostgreSQL 18. It shards tables across servers, keeps tamper-evident ledger tables, and puts a web console on every node. One package: install it and the node has everything.

PostgreSQL License Read and write on any node Sharding lives in an extension, not the executor
kingres.buckets3 servers · 48 buckets
Illustration. In KingresDB the bucket of a key is compute_partition_hash_value(key) % bucket_count, the value PostgreSQL itself uses to store the row, so routing and storage cannot disagree.
  • 18.7PostgreSQL base (tag REL_18_7), changed only through a short register of core patches
  • 4extensions: kingres_shard, kingres_ledger, kingres_sketch, kingres_timepart
  • 5,151TAP subtests behind kingres_shard 0.3, on real multi-node clusters
  • 1package with the server, the extensions, kingresd and the console
Why KingresDB

Three additions to PostgreSQL. Everything else stays PostgreSQL.

Your SQL, types, indexes, extensions and tools keep working. KingresDB adds what one server cannot give you: more servers behind one database, a history that can be checked from the outside, and a console to run it all.

Sharding

kingres_shard

Tables are split into a fixed number of hash buckets spread over several servers. A statement that touches one key goes straight to the group that owns it. A statement that spans groups is answered by reading the others.

How sharding works

Tamper-evident ledger

kingres_ledger

Ledger tables record every change in a hash chain of Merkle blocks. Keep one digest outside the database and anyone can later detect a rewritten history, or prove that a single row version was there.

How the ledger works

A console on every node

kingresd

Every server runs the same agent: a web console and a REST API to create or join a cluster and to manage databases, roles, servers, certificates and network access. No separate management host.

Tour the console
Start simple

One function call turns a table into a distributed table.

Start on one node. Add servers when you need them. The application keeps talking SQL to whichever node it likes.

  • Distributed tables. Hash-partitioned by a column you choose; each shard group holds the partitions of its buckets.
  • Reference tables. Small tables kept in full on every node. Reads are local, writes reach every node in one transaction.
  • Colocation. Tables that share a distribution key land in the same buckets, so a join on the key runs inside one group.
  • DDL that travels. ALTER TABLE, CREATE INDEX and grants are propagated to every node atomically.
Create a cluster and distribute a table
-- on the first node (it becomes the map group primary)
CREATE EXTENSION kingres_shard;
SELECT kingres.init_cluster('host1', 5432);

-- each new primary is a new shard group
SELECT kingres.add_node('host2', 5432);
SELECT kingres.add_node('host3', 5432);

-- distribute a table, and keep a small one everywhere
CREATE TABLE users (id int, name text, PRIMARY KEY (id));
SELECT kingres.create_distributed_table('users', 'id');

CREATE TABLE countries (code text PRIMARY KEY, name text);
SELECT kingres.create_reference_table('countries');

-- from any node
INSERT INTO users VALUES (42, 'ada');
SELECT name FROM users WHERE id = 42;          -- one group
SELECT count(*) FROM users;                    -- every group
EXPLAIN SELECT name FROM users WHERE id = 42;  -- shows where it runs
Add a server and move buckets onto it
-- a fourth server joins as a new, empty shard group
SELECT kingres.add_node('host4', 5432);

-- which moves would even out the buckets per group?
SELECT * FROM kingres.rebalance_plan();

-- move one bucket: copy, catch up with logical replication,
-- then a two-phase switch (detach on the source, attach on the target)
SELECT kingres.move_bucket(1, 17, 3);   -- colocation, bucket, target group

-- drain a server before removing it
SELECT kingres.set_node_property(4, false);  -- should_have_shards

-- one row per inconsistency; no rows when the cluster is sound
SELECT * FROM kingres.check_cluster();
SELECT * FROM kingres.buckets;
Put a table under ledger control and verify it
CREATE EXTENSION kingres_ledger;

-- append-only by default; 'updatable' keeps every old version provable
SELECT kingres.ledger_enable('public.accounts');
SELECT kingres.ledger_enable('public.balances', 'updatable');

INSERT INTO accounts VALUES (1, 'ada', 100);   -- captured by a trigger

-- a background worker builds a block about every 10 seconds
SELECT kingres.ledger_generate_digest();   -- store the result OUTSIDE the database

-- later: is the chain intact, and does it match the digest I kept?
SELECT * FROM kingres.ledger_verify();             -- no rows when consistent
SELECT kingres.ledger_verify_digest('{...}');

-- prove that one row version is part of the ledger
SELECT kingres.ledger_inclusion_proof('accounts', kingres.ledger_row_hash(a.*))
  FROM accounts a WHERE id = 1;
Distinct counts, top-n and percentiles in bounded memory
CREATE EXTENSION kingres_sketch;

-- HyperLogLog: how many distinct visitors?
SELECT kingres_sketch.approx_count_distinct(user_id) FROM events;

-- t-digest: the 99th percentile of latency
SELECT kingres_sketch.approx_percentile(0.99, latency_ms) FROM requests;

-- Space-Saving: the ten most requested paths
SELECT * FROM kingres_sketch.topn_list(
  (SELECT kingres_sketch.topn_add_agg(path) FROM requests), 10);

-- sketches are values: store one per day, merge them later
SELECT kingres_sketch.hll_cardinality(kingres_sketch.hll_union_agg(visitors))
  FROM daily_rollup WHERE day >= '2026-11-01';
Create partitions ahead of time and retire old ones
CREATE EXTENSION kingres_timepart;

CREATE TABLE events (at timestamptz NOT NULL, payload jsonb)
  PARTITION BY RANGE (at);

-- daily partitions, a week ahead, dropped after 90 days
SELECT kingres.timepart_set_policy('events',
  partition_every => '1 day',
  create_ahead    => '7 days',
  retention       => '90 days');

SELECT * FROM kingres.timepart_plan('events');   -- what a run would do
CALL kingres.timepart_run('events');             -- do it, with a run history

SELECT * FROM kingres.timepart_partitions('events');
SELECT * FROM kingres.timepart_policies;
What is in the box

Built as extensions on a small, documented fork.

The sharding and ledger logic live in extensions. The fork itself stays thin, so following upstream PostgreSQL stays cheap.

Statement routing

A planner hook sends single-key statements to the owning group as a Kingres Remote Statement. On a one-group cluster nothing changes.

Shipped

Distributed scan

A SELECT that spans groups reads local buckets plus one fragment per other group, in batches. Every query shape is answered correctly.

Shipped

Two-phase commit

A transaction that writes on several nodes commits on all or none. A recovery worker resolves anything a crash left prepared.

Shipped

Bucket moves

move_bucket copies a bucket, replays changes with logical replication, proves the copy is complete and switches owners in two phases.

0.3, in review

Standalone verifier

kingres-verify checks digests and proofs without trusting the database. Standard-library Go, about 2,000 lines an auditor can read.

Shipped

Approximate aggregates

HyperLogLog distinct counts, Space-Saving top-n and t-digest percentiles, written from the published algorithms.

1.0, new

Time partitioning

Policies for ordinary partitioned tables: create partitions ahead, drop or detach old ones, and keep a history of every run.

0.1, new

Secure by construction

Servers talk over mutual TLS under a cluster CA. Console accounts are PostgreSQL roles. Network logins are refused until you allow them.

Shipped
How it works

Every server is a full member. Connect to any of them.

Each server hosts a PostgreSQL primary with its own buckets and a kingresd agent. The catalog is authoritative on the map group and copied to every node, so every node can plan and route.

PATH 1One key, one group

WHERE id = 42 belongs to one bucket. If this node owns it, PostgreSQL's planner runs as usual. Otherwise the statement is deparsed and run on the owner.

PATH 2Reads across groups

PostgreSQL plans the query as if all data were local. Each distributed table is read by a Kingres Distributed Scan, and restrictions are rechecked here.

PATH 3Writes across groups

An UPDATE or DELETE that can be shipped whole runs on every group that owns buckets of the table, under two-phase commit.

PATH 4Stale map? Retry.

A forwarded session never trusts the sender's placement. If a bucket has moved it raises KS001; the origin reloads the catalog and retries once.

Tamper-evident ledger

A history that can be checked from outside the database.

Put a table under ledger control and every change is hashed into a chain of blocks. Export a digest, keep it somewhere the database cannot reach, and you hold the root of trust.

Append-only or updatable

Append-only tables accept inserts only. Updatable tables allow UPDATE and DELETE, with every removed version kept in a history table and still provable.

Blocks, digests, proofs

Background workers build Merkle blocks on an interval. ledger_generate_digest exports the head; ledger_inclusion_proof shows that one row version is part of the ledger.

Hard to switch off by accident

Enabling the ledger is permanent. DROP TABLE, DROP SCHEMA … CASCADE and DROP EXTENSION are rejected while a ledger table exists.

What it promises, plainly. The ledger makes tampering detectable, not impossible. Someone who can rewrite the database files can rewrite the chain too; what they cannot do is make it match a digest you stored elsewhere. That digest, kept outside the database, is the root of trust.
Web console

Open port 8091 on any server and run the cluster from there.

The console is a Vue single-page application embedded in kingresd, generated against the same OpenAPI contract the REST API is checked with. Pick a page to see what it does.

http://127.0.0.1:8091/dashboard

A guide to the console's pages, drawn as a schematic. It is not a screenshot.

First run in a browser

A new node starts uninitialized and writes a one-time setup token. Enter it, then create a cluster or join one.

Accounts are PostgreSQL roles

Sign in with a database role. What you may do follows role membership such as kingres_admin and kingres_ops.

Pinned certificates

Adding or joining a server asks for the peer's certificate fingerprint. Unpinned joins are refused unless you say so explicitly.

Bring your own Prometheus

No bundled metrics store. kingresd keeps a short history for the charts and exposes /metrics.

Use cases

What people build on a database like this.

01

Multi-tenant SaaS

Distribute every tenant-owned table by the tenant id and colocate them. A tenant's rows share buckets, so its queries and joins run inside one shard group, and shared lookup data lives in reference tables.

create_distributed_tablecolocate_withcreate_reference_table
02

Records that must stand up to an audit

Payments, balances, approvals, medical or legal records. Keep them in ledger tables, export digests on a schedule, and hand an auditor a proof they can check on their own machine.

ledger_enableledger_generate_digestkingres-verify
03

Real-time analytics

Dashboards over event streams rarely need exact answers. Count distinct users, rank the top items and read percentiles from sketches that stay small and merge across days.

approx_count_distincttopn_add_aggapprox_percentile
04

Time series and event data

Let a policy create tomorrow's partitions before the data arrives and retire last quarter's when it is no longer needed. Each run is recorded, so you can see what was created and dropped.

timepart_set_policytimepart_rundrop_old_time_partitions
Stated plainly

What KingresDB guarantees today, and what it does not yet.

A database earns trust by being exact about its limits. These come straight from the extension documentation and the independent reviews in the repository.

Guaranteed

  • Atomic commit across nodes.Multi-node writes use two-phase commit. The local commit is always flushed before the first remote commit is sent.
  • Atomic catalog changes and DDL.Adding a node, distributing a table and propagated DDL change all nodes in one transaction under a cluster-wide lock.
  • Correct answers for every query shape.The row-moving distributed scan stays as the path that can answer any query, whatever faster paths are added.
  • Text that means the same everywhere.Forwarded statements are deparsed so that session settings on either node cannot change their meaning.
  • Detectable tampering.A change to ledger history is found by verification against a digest held outside the database.

Not yet

  • No global snapshot.Each node commits at its own moment, so a cross-group read can see a transaction on one group before another. SERIALIZABLE is per node.
  • No distributed deadlock detection.Fan-out writes lock in node order and do not deadlock each other. For anything else, set lock_timeout.
  • Some statements are refused.A multi-row INSERT or INSERT … SELECT whose rows belong to several groups gets a clear "not supported yet" error.
  • Tables are distributed while empty.Distributing a table that already has rows is on the roadmap.
  • Failover is in progress.Standbys, leases and automatic failover are being built. Do not run production on it yet.
Status and roadmap

Where the project is.

Each phase ships with its tests, its documentation and an independent review. The dated work log in the repository records what was done and how it was verified.

Sharding corekingres_shard 0.1 – 0.2

Catalog and bucket map, statement routing, distributed scan, fan-out writes, reference tables, two-phase commit with a recovery worker, DDL propagation.

Shipped

Ledgerkingres_ledger 0.2 · kingres-verify

Append-only and updatable ledger tables, block-building workers, digests, inclusion proofs, recorded verifications and the standalone verifier.

Shipped

Control plane and consolekingresd · REST contract 0.7

Create or join a cluster, databases, roles and grants, network access, certificates, audit log, cluster-wide logs and alerts, SQL workbench, task engine.

Shipped

PackagingDocker image · Debian package

One reproducible build recipe, a non-root container image, a three-node compose cluster and a .deb with a systemd unit for Ubuntu 24.04.

Shipped

Bucket movementkingres_shard 0.3

move_bucket, rebalance_plan, check_cluster. Fixes for the review's findings are under way; the console's rebalance operations follow.

In review

High availabilityphase 5

A standby for every shard group with chained placement, failover inside kingresd fenced by majority leases, and a client proxy port.

In progress

Analytics extensionskingres_sketch 1.0 · kingres_timepart 0.1

Approximate aggregates and time-partition policies are in the tree. Columnar storage, repartitioned joins and MERGE on distributed tables are designed.

In progress

PostgreSQL 19one extension source, two majors

Every extension builds and is tested against PostgreSQL 18 and 19 from the same source, with a product branch per major.

In progress

Faster pathsphase 2b

Aggregate, sort and limit pushdown, colocated joins, and a row router for multi-row INSERT, INSERT … SELECT and COPY FROM.

Designed

Table lifecycle and elasticityphases 9 – 11

Distribute tables that have rows, undistribute, change the distribution column; split buckets, rebalance in the background, drain a server; schema-based sharding.

Designed

Signing and anchoringphase 7

Signed digests, external anchoring to write-once storage and timestamp authorities, and one aggregate digest across shard groups.

Planned
Get started

From a clone to a running node in three commands.

Build the image from the repository, start a node, and finish the setup in your browser. Tested on Ubuntu 24.04 and on Windows 11 with WSL2.

  • Nothing baked in. The setup token is created at first start, inside the volume.
  • Closed by default. The instance accepts no network login until you add a rule on the console's network access page.
  • Runs locked down. Non-root, read-only root filesystem, all capabilities dropped.
Developer setup guide
Docker
git clone https://github.com/KingresDB/Kingres.git
cd Kingres

docker build -f kingres/packaging/docker/Dockerfile -t kingres:0.1.0 .

docker run -d --name kingres --stop-timeout 120 \
  -p 127.0.0.1:8091:8091 -p 127.0.0.1:5432:5432 \
  -v kingres-data:/var/lib/kingres kingres:0.1.0

# the one-time setup token
docker exec kingres cat /var/lib/kingres/setup-token
Docker Compose
cd Kingres/kingres/packaging/docker

# kingres-1, kingres-2, kingres-3 on one network
docker compose up --build -d

# setup token and console URL of each node
./tokens.sh

# consoles:  127.0.0.1:8091  8092  8093
# databases: 127.0.0.1:5432  5433  5434

docker compose stop          # clean shutdown of the databases
Ubuntu 24.04, amd64
cd Kingres/kingres/packaging

# build the release tree, then the package
build/build.sh
deb/build-deb.sh

sudo apt install ./kingres_0.1.0-*_amd64.deb
sudo systemctl status kingres.service

# then open the console on port 8091
STEP 1Open the console

Go to 127.0.0.1:8091 and enter the setup token.

STEP 2Create a cluster

kingresd creates the instance, the administrator role and the system database.

STEP 3Add servers

Join more nodes from the Servers page, then distribute your tables.

Open source, under the PostgreSQL License.

The design, the decision records, the reviews and the work log are all in the repository. Read them, run the tests, and tell us what breaks.