# Stolon — the whole site as Markdown > Stolon is a serverless, Postgres-compatible database for teams building AI agents and the applications they serve. Nothing is overwritten: read any table at a past moment (`FOR SYSTEM_TIME AS OF`), branch the whole database in O(1), compare any two states, merge a branch back with conflicts named by table, row and column, and restore to a moment. Stock Postgres clients work unchanged; the database name in the connection string selects the branch. Agents can also use it over MCP. Generated from the HTML pages at https://stolondb.com. Each section below is one page; its source URL is on the line under its heading. --- # A serverless, Postgres-compatible database with no cold starts. > A serverless, Postgres-compatible database with no cold starts, for teams building AI agents and the apps they serve. Every branch is instant, history is queryable, and branches merge back with a reviewable diff. Source: https://stolondb.com/ · Page title: Stolon — serverless, Postgres-compatible database for AI agents, with branches and history For teams building AI agents and the apps they serve. Branches are instant, merge back as a diff you review, and the past is one query away. [Start free](https://stolondb.com/signup) [Read the docs](https://stolondb.com/docs/) Free while in preview. Works with psql, psycopg, node-postgres, SQLAlchemy, Alembic and any MCP client. ## Everything an agent does to your data happens on a branch you can review and undo. Your app and your agents share one versioned database. ### A branch for every agent and every pull request The whole database, instantly, under a name you connect to. Nothing written there shows up on `main`. ``` acme.main=> CREATE DATABASE "agent-triage-4127"; CREATE DATABASE ``` ### Undo, and read any moment back Read any table as it was at a time you name, or put a branch back to before an agent ran. ``` acme.main=> SELECT * FROM tickets acme.main-> FOR SYSTEM_TIME AS OF '2026-10-01 09:00:00+00'; ``` ### Review and merge what agents changed Every branch is a pull request of the rows and cells it changed. A conflict names the table, row and column, and nothing lands until you decide. [Connect GitHub](https://stolondb.com/guides/github/) and every pull request gets its own branch. ``` conflict | customers[1].seats, both sides ``` ### Postgres drivers for your app, MCP for your agents Your stack connects unchanged, and the database name picks the branch. Agents get a versioned key-value store over MCP. ``` postgresql://app:…@db.stolondb.com/acme.agent-triage-4127 ``` ![The console's pull request for the branch migrate-seat-billing into main: one conflict on customers row 1, seats, where main says 16 and the branch says 14; two rows modified, including Lumen Robotics' plan changed from free to team; and one new column, billed_seats.](https://stolondb.com/assets/shot-changes-light.webp) ``` $ psql "postgresql://app:…@db.stolondb.com/acme.main" acme.main=> CREATE DATABASE "migrate-seat-billing"; CREATE DATABASE acme.main=> MERGE DATABASE "migrate-seat-billing" acme.main-> INTO main DRY RUN; ``` ## Why it is called stolon A stolon is a plant's runner: each node on it can root into a plant of its own. `main` is the runner and a branch is a node that has rooted. A runner never takes a plant back. Stolon can, and that is a merge. ## How teams use it Three workflows that need a copy of real data. ### Agents exploring in parallel A branch per run. Merge the one you keep, drop the rest. [Review an agent's changes](https://stolondb.com/guides/review-agent-changes/) ### A preview database per pull request CI makes a branch per pull request and the preview connects to it by name. [Branch per pull request](https://stolondb.com/guides/branch-per-pull-request/) ### Migrations you rehearse first Migrate a branch of production, read the diff, then merge it or throw it away. [Rehearse a migration](https://stolondb.com/start/) ![The console's overview: main as a line running left to right, with three branches leaving it (migrate-seat-billing and preview-pr-218 ready to review, agent-triage-4127 in progress) and a list of pull requests ready to review.](https://stolondb.com/assets/shot-overview-light.webp) ## How it compares From each vendor's own pages. | | Stolon | Neon | Supabase | Dolt | | --- | --- | --- | --- | --- | | A branch is | the whole database, made without copying it | a copy-on-write clone with its own compute | a separate environment that starts without data by default | a branch of a versioned database | | Merging data back | yes, with conflicts named by row and column | not described; a branch is reset or restored | applies migrations; no data merge described | yes, in SQL | | When idle | stays awake; no cold start | compute scales to zero after 5 minutes on Free and Launch | a Free project pauses after a week | each hosted database is a dedicated instance | | Reading the past | any table at any moment in the window, in SQL; compare two moments | restore within a history window | daily backups; point-in-time recovery as an add-on | diffs between commits through system tables | *Vendor facts as of 26 September 2026; hosted Dolt as of 30 September 2026. [Read the full comparisons](https://stolondb.com/compare/).* ## Pay for what your agents do. Metered on throughput and storage held. Idle time isn't billed. ### Free To try it - Databases **1** - Live branches **up to 10** - History **24 hours** ### Team App teams and early agent work - Branches **no per-branch fee** - History **7 days** - Review and merge **policies, approvals** ### Agents Agent fleets in production - Branches **no per-branch fee** - History **30 days** - Provenance **checks, watchpoints** Enterprise on request; provisioned production databases coming Free during the preview; prices published at launch. [Compare the plans](https://stolondb.com/pricing/) ## Give every agent its own database. Name a database and connect with the driver you already use. [Start free](https://stolondb.com/signup) [Read the docs](https://stolondb.com/docs/) --- # Start where you are. > Three ways in: rehearse on an imported copy of the Postgres you keep, start a new app on Stolon, or move an app here from another provider. Source: https://stolondb.com/start/ · Page title: Get started with Stolon — start with a copy, not a migration A Stolon database speaks Postgres, and every branch inside it is an instant copy of the database. **Databases are free while Stolon is in preview.** Name a database and you get a connection string. [Start free](https://stolondb.com/signup) *Already have an account? [Sign in](https://stolondb.com/login).* ## Three ways in ### Rehearse: you have Postgres and you are keeping it Import a copy, branch it per migration or per agent, and ship what you keep back to Postgres. ### Start here: greenfield, with no upstream Build something new with Stolon as the system of record. ### Move here: you are on a provider and want out A `pg_dump` from Neon, Supabase, RDS or Heroku imports. First, [run the compatibility gate against your schema and queries](https://stolondb.com/compatibility/). ## What the first hour looks like 1. **Sign up, name a database, create an app password** Copy the connection line; the password is shown once. The database name is `.`, and the default branch is `main`. ``` $ psql "postgresql://app:@db.stolondb.com/acme.main" ``` 2. **Load your data** Import a `pg_dump` from the console, or create tables from scratch. 3. **Branch, and do the frightening thing there** ``` acme.main=> CREATE DATABASE rehearsal; CREATE DATABASE # connect with dbname=acme.rehearsal $ alembic upgrade head ``` 4. **Review, then merge** The branch shows up in the console as a pull request. Or from SQL: ``` acme.main=> MERGE DATABASE rehearsal acme.main-> INTO main DRY RUN; kind | detail ------------------+-------------------------------- conflict | accounts[1].balance, both sides rows to apply | 2 deletes to apply | 0 acme.main=> MERGE DATABASE rehearsal acme.main-> INTO main RESOLVE OURS; ``` ## And you can see it Every database has a console, with pull requests, the Time Machine and a SQL tab. ![The console overview: main, what your app connects to, above a list of branches, each with what it changed and a button to review its changes.](https://stolondb.com/assets/console-overview.png) *main and its branches, with what each one changed.* ![A pull request in the console: the conflicting rows named down to the column, with the value on each side shown beside the other.](https://stolondb.com/assets/console-merge.png) *A pull request: every conflict named down to the row and column, with both values.* ## Durability Nothing acknowledged is lost to a process crash, kill-9 or power loss. ## What it costs Throughput and storage held, with no per-branch fees on paid plans. Free in preview. [The plans](https://stolondb.com/pricing/). [Start free](https://stolondb.com/signup) - [Docs](https://stolondb.com/docs/) — Compatibility, merge, durability and auth. --- # Make a database, branch it, merge it back. > Connect, branch, merge and read history in Stolon: the SQL verbs, Postgres compatibility, auth and the console. Source: https://stolondb.com/docs/ · Page title: Stolon docs — connect, branch, merge Six steps from nothing to a merged pull request, then the reference. For one task at a time, see [the guides](https://stolondb.com/guides/). ## Get started 1. **Create a database** [Sign up](https://stolondb.com/signup), confirm your address and name a database. 2. **Create an app password** On the database's page, **Create an app password**. It is shown once, so copy it then. Revoke one to cut it off. 3. **Connect** Any Postgres client. The database name picks the branch: `.`. Your app uses `main`. ``` $ psql "postgresql://app:@db.stolondb.com/acme.main" ``` 4. **Branch** A branch is an instant copy of the whole database. Connect to it by name and change anything. ``` acme.main=> CREATE DATABASE price_change; CREATE DATABASE $ psql "postgresql://app:@db.stolondb.com/acme.price_change" ``` 5. **Review it as a pull request** In the console, a branch with changes is a pull request: every row it added, changed or removed, and anything that conflicts with `main`. 6. **Merge** Merge from the pull request, or from SQL. `DRY RUN` shows what would land without landing it. ``` acme.main=> MERGE DATABASE price_change INTO main DRY RUN; acme.main=> MERGE DATABASE price_change INTO main; ``` ## Connect Any Postgres driver connects unchanged, with the branch as the database name: ``` # python >>> import psycopg >>> psycopg.connect("postgresql://app:PASSWORD@HOST:PORT/acme.staging") # sqlalchemy + alembic $ DATABASE_URL="postgresql+psycopg://app:$PASSWORD@$HOST:$PORT/acme.staging" alembic upgrade head ``` ### Short-lived tokens, for CI and agents Exchange an API key from your Account page for a token scoped to one database, valid for up to 24 hours. Use it as both user and password. ``` $ TOKEN=$(curl -s https://console.stolondb.com/v1/tokens \ -H "Authorization: Bearer $STOLON_API_KEY" \ -d '{"store":"acme","sub":"ci","scopes":["query","data","branch"],"ttl":3600}' | jq -r .token) $ psql "postgresql://$TOKEN:$TOKEN@db.stolondb.com/acme.main" ``` `scopes`: `query` (read), `data` (write), `branch` (create, merge and drop branches). `ttl` is seconds, up to 86,400. ## Postgres compatibility Every SQL behavior is checked against a live PostgreSQL on every test run: **210 script families**, compared on rows, command tags, error codes and transaction status. | Area | | Detail | | --- | --- | --- | | Wire protocol | works | simple and extended, binary parameters and results, SCRAM-SHA-256 | | Clients | works | psql, psycopg2, psycopg3, pgJDBC | | ORMs and migrations | works | SQLAlchemy 2.0, Alembic including autogenerate | | Queries | works | all join kinds, subqueries, CTEs incl. `WITH RECURSIVE`, set operations, GROUP BY/HAVING/FILTER, DISTINCT ON | | Window functions | works | `row_number`, `rank`, `lag`, `lead`, aggregates with `OVER`, named windows, ROWS/RANGE/GROUPS frames | | Transactions | works | savepoints, Postgres abort semantics | | Constraints | works | NOT NULL, UNIQUE, CHECK, FOREIGN KEY with every action, enforced | | Schema | works | ALTER TABLE, views, sequences, SERIAL/IDENTITY, indexes incl. partial, generated columns, enums, schemas | | Upserts | works | `ON CONFLICT … DO UPDATE / DO NOTHING`, `ON CONSTRAINT` | | Roles, grants, RLS | works | CREATE ROLE, SET ROLE, GRANT/REVOKE, row-level security policies | | PL/pgSQL, procedures, triggers | works | functions, `DO` blocks, cursors, exception blocks, row and statement triggers | | Types | works | integers, `numeric`, floats, text, `boolean`, dates, timestamps, intervals, `uuid`, `bytea`, `json`/`jsonb`, arrays | | Functions | works | string, regex, date/time (`date_trunc`, `to_char`, `AT TIME ZONE`), JSON (`->>`, `jsonb_set`, `jsonb_agg`), `generate_series`, `LANGUAGE sql` functions | | Extensions | works | `vector` (pgvector, `ivfflat`, `hnsw`), `pgcrypto`, `citext`, `hstore`, `pg_trgm`, `uuid-ossp`, `unaccent`, `fuzzystrmatch` | | Tooling | works | psql backslash commands (`\d`, `\dt`, `\l`), `COPY` and `\copy` in text and CSV, pg_catalog and information_schema | ### Differences from Postgres - `int2`, `int4` and `int8` are one 64-bit integer; `real` and `double precision` are one float. `NUMERIC` is exact. - Sequences are branch-local and transactional. - Identifiers are not truncated at 63 bytes. ## Moving data in and out ``` # in: a real pg_dump $ pg_dump --no-owner mydb | stolon-db /path/to/store --import main # out: back to Postgres, any branch $ stolon-db /path/to/store --export staging | psql -d restored # will this run here? ask before you migrate $ cat queries.sql | stolon-db /path/to/store --compat-check main ``` On a hosted database, import and export from the console or its HTTP API. An import lands in a new branch. ## Branching and history | Statement | What it does | | --- | --- | | CREATE DATABASE b | instant fork of the connected branch: schema, data and history | | CREATE DATABASE b (schema only) | the structure, every table empty | | DROP DATABASE b | drops it; a protected branch refuses | | MERGE DATABASE b INTO main | merges the branch back (below) | | SELECT … FOR SYSTEM_TIME AS OF t | any table at any moment, on any branch | | COMPARE DATABASE a [AS OF t] WITH b [AS OF t] | rows added, removed and modified between two states, then `ROWS` or `CELLS` | A branch can start from a past moment, and can be restored to one. The console's Restore keeps the present as a branch first, so a restore can be undone. [The history guide](https://stolondb.com/guides/history/) walks through it. Protect, expire and reset are in the console and the HTTP API. ## Merging `MERGE DATABASE b INTO main [RESOLVE OURS|THEIRS] [DRY RUN]` - **Column-level.** Changes to different columns of the same row both land. - **Atomic.** A conflict refuses the whole statement. - **Specific.** Conflicts are named `table[pk].column`, with both values. - **Schema merges too.** A column added on the branch arrives with the merge. - **`RESOLVE OURS|THEIRS`** settles value conflicts; `DRY RUN` previews it. - **Repeatable.** A branch can be merged again and again. ## Durability - Every commit is durable before it is acknowledged. - Every page is checksummed; a damaged page is never served. - Online backup, consistent, while serving. - Log shipping: `--archive DIR` with `--archive-command` to your uploader, and `--restore-from DIR` to roll forward. ## Access control - **SCRAM-SHA-256** on the wire, TLS at the edge. - **Grants and policies branch** with the schema; roles are global. - **Fork, merge and drop are grantable privileges.** - **API tokens carry scopes** (`read`, `query`, `data`, `branch`, `backup`, `admin`). A data credential can never reset a database. - **An audit trail** records every branch and merge. ## Agents and MCP Every database serves MCP at `https://console.stolondb.com/mcp/`. An agent gets a key-value store where every write is a version, and can review and merge the database's branches. Add it to Claude, ChatGPT, Claude Code or Cursor and sign in; [the MCP guide](https://stolondb.com/guides/mcp/) has each. A branch can also carry references, such as a git SHA or an image digest, and decisions recording why it is the way it is. Both fork, merge and roll back with the data. ## The console Open a database from [the dashboard](https://console.stolondb.com/app). ![The console overview: main, what your app connects to, above a list of branches, each with what it changed and a button to review its changes.](https://stolondb.com/assets/console-overview.png) *Fig. 1 — the overview: `main` and its branches.* ![The console's version tree: every branch drawn at the depth it forked from, beside the database's health.](https://stolondb.com/assets/console-plate.png) *Fig. 2 — the version tree, beside the database's health.* A `read` token sees branches, the version tree and health; `query` also sees rows, history and pull requests. ## Deployment - **Hosted.** A database we run, with the console and the log shipped off the machine continuously. - **Single-tenant binary.** One process, one database, with local credentials, an audit trail and the built-in console. - [Get a database](https://stolondb.com/start/) — Import a copy, branch it, ship back. --- # Will your app run on Stolon? > Point the compatibility gate at your own schema and queries. It reports which statements will not run here, with the SQLSTATE and the reason, before you move anything. Source: https://stolondb.com/compatibility/ · Page title: Will your app run on Stolon? The compatibility gate Point the compatibility gate at your own schema and queries before you move anything. ## Run it **On the hosted service**, load your schema into a branch and run your queries there. Nothing reaches `main`: ``` # 1. a branch to probe in, and your schema in it $ psql "postgresql://app:@db.stolondb.com/acme.main" -c 'CREATE DATABASE probe' $ pg_dump --schema-only "$DATABASE_URL" | psql "postgresql://app:@db.stolondb.com/acme.probe" # 2. your queries — a log, an ORM dump, a file you wrote by hand $ psql "postgresql://app:@db.stolondb.com/acme.probe" -f queries.sql ``` Any statement that won't run is refused with its SQLSTATE and the reason. ## What works | Area | Status | Notes | | --- | --- | --- | | Ordinary CRUD, joins, CTEs, aggregates, transactions | supported | the bulk of most applications | | Constraints: NOT NULL, UNIQUE, CHECK, foreign keys | supported | enforced | | Roles, GRANT/REVOKE, row-level security | supported | policies branch with the schema | | Upserts: `ON CONFLICT (email) DO UPDATE` | supported | on the primary key or any unique column | | String functions: `left`, `substring`, `replace`, `concat`, `lpad`, `split_part`… | supported | also `format`, `md5` and regular expressions | | Dates: `now() - interval '7 days'`, `extract`, `date_trunc`, `to_char` | supported | also `interval` columns, `AT TIME ZONE` and `SET TIME ZONE` | | Window functions: `row_number`, `rank`, `lag`, `sum(x) OVER (…)` | supported | named windows and `ROWS`, `RANGE` and `GROUPS` frames | | JSON: `->`, `->>`, `@>`, `\|\|`, `jsonb_set`, `jsonb_build_object`, `json_agg` | supported | including whole rows: `row_to_json(t)` | | Enum types, schemas, partial indexes | supported | reflected the way ORMs expect | | PL/pgSQL functions, procedures, triggers | supported | also `DO` blocks and `CALL` | | Extensions: `vector`, `pgcrypto`, `citext`, `hstore`, `pg_trgm`, `uuid-ossp` | supported | pgvector with `ivfflat` and `hnsw`; also `unaccent`, `fuzzystrmatch` | | psql's `\d` metacommands | works | `\dt`, `\d`, `\di`, `\df`, `\du` and more | The full surface is in [the docs](https://stolondb.com/docs/). Gate came back green? The next step is a database. [Start free](https://stolondb.com/signup) - [Get a database](https://stolondb.com/start/) — Rehearse, start here, or move here. - [Docs](https://stolondb.com/docs/) — Merge, branch verbs, durability and auth. --- # One storage engine, built for branches > Stolon is its own storage engine behind the PostgreSQL wire protocol: instant branches, history, merge, durability, and what has been measured. Source: https://stolondb.com/how-it-works/ · Page title: How Stolon works: architecture for engineers Stolon is its own storage engine, a fully persistent B-tree, behind the PostgreSQL wire protocol. It is not a Postgres fork. ## The shape of it - **Clients** speak the PostgreSQL wire protocol (psql, psycopg, node-postgres, SQLAlchemy, Alembic) or MCP. The database name in the connection string selects the branch. - **The SQL layer** is judged against a live PostgreSQL on every test run: **210 script families**, comparing rows, command tags and errors. [Check your own queries.](https://stolondb.com/compatibility/) - **The engine** keeps every committed state readable, and any of them can start a new branch. Schema changes branch and merge with the rows. *Diagram: main runs left to right as a line of commits. At one past moment a branch drops away; a bracket above main spans from that moment to now and is labeled compare; a dotted arc under main runs from now back to the moment and is labeled restore, and a branch dropping from now keeps the present.* *Read, branch from or compare any moment on `main`. Restore keeps the present as a branch first.* ## Branches A branch copies no rows and no pages, whatever the size of the data. A read on a branch costs what a read on `main` costs, however deep the branch sits and however many siblings it has. [More on fully persistent B-trees](https://stolondb.com/blog/fully-persistent-b-tree/). ## History `FOR SYSTEM_TIME AS OF` reads any table as it was at a past moment. `COMPARE DATABASE` shows what changed between two moments and says its plan before it reads. History is kept for your plan's window. ## Merge `MERGE DATABASE b INTO main` is a three-way merge, decided column by column, so a backfill on a branch and live traffic on `main` compose. It is atomic: a conflict applies nothing and names the row and column, and `DRY RUN` previews the whole result. ![The console's review of migrate-seat-billing into main: one conflict to decide on customers row 1, seats (12 before either change, 16 on main, 14 on the branch), with a button to keep each side or type a value, and nothing merged until it is decided.](https://stolondb.com/assets/shot-merge-light.webp) *A conflict in the console. Nothing is applied until every conflict is decided.* ## Durability - A commit is acknowledged only once it is on disk, and every acknowledged write survives a SIGKILL. - Every page is checksummed. A damaged page is never served. - The log can be shipped to object storage as it is written. Restored from the bucket alone after `kill -9` with every local file deleted, a database lost no acknowledged write. - A read-only standby follows a database and can be promoted. ## What has been measured | Property | Result | | --- | --- | | Branch creation | 27.4 ns → 28.8 ns per branch from 1,000 to 100,000 branches (1.10x) | | Depth | reads on a branch 125 levels deep cost what reads on `main` cost | | Width | a read scans 2,100 entries and 16 pages at 100, 1,000 and 10,000 live branches | | Crash recovery | 61 crash points: 30 roll back, 31 roll forward, 0 corrupt | | Larger than memory | 5.3x memory on disk, reads flat across 100 levels of depth on a cold cache | | Throughput | 5,648 durable writes/s and 11,504 reads/s at 64 connections | | Idle | an idle, empty database is 3.23 MB of memory and 20 KB of disk | | Against Doltgres | on an external benchmark's agent-exploration workload: 1.14x total time, 1.03x branch creation, 4.0x less storage on a deep branch spine | *A test in the repository reproduces each result.* - [Fully persistent b-trees](https://stolondb.com/blog/fully-persistent-b-tree/) — What the term means for a database. - [Docs](https://stolondb.com/docs/) — The dialect, merge, branch verbs, durability and auth. --- # Guides > Short, tested task pages for Stolon: connect from psql, Python and Node.js, a database branch per pull request, reviewing and undoing an agent's changes, LangGraph's checkpointer, and MCP. Source: https://stolondb.com/guides/ · Page title: Stolon guides — connect, branch, review, undo One task per page. Every command was run as written. ## Connect Copy the connection string from your database's page. **The database name selects the branch**: `.`, as in `acme.main`. ```text postgresql://app:@db.stolondb.com/acme.main ``` ## Tasks The first creates the `accounts` table the next five use. - [Connect from psql, Python and Node.js](https://stolondb.com/guides/connect/) - [Connect a GitHub repository](https://stolondb.com/guides/github/) - [A database branch for every pull request](https://stolondb.com/guides/branch-per-pull-request/) - [Review an agent's changes as a pull request](https://stolondb.com/guides/review-agent-changes/) - [Undo what an agent wrote](https://stolondb.com/guides/undo-agent-writes/) - [Use Stolon as LangGraph's checkpointer](https://stolondb.com/guides/langgraph-checkpointer/) - [Connect an AI agent over MCP](https://stolondb.com/guides/mcp/) - [Read, branch, compare and restore a past moment](https://stolondb.com/guides/history/) See also [the docs](https://stolondb.com/docs/) and [Will it run?](https://stolondb.com/compatibility/) --- # Connect from psql, Python and Node.js > Stolon speaks the PostgreSQL wire protocol, so psql, psycopg, psycopg2, SQLAlchemy, node-postgres and postgres.js connect unchanged. The database name in the connection string selects the branch. Source: https://stolondb.com/guides/connect/ · Page title: Connect to Stolon from psql, Python and Node.js Your Postgres driver connects unchanged. **The database name selects the branch.** ## The connection string Copy it from your database's **Connect** page. The database name is `.`: ```text postgresql://app:@db.stolondb.com/acme.main ``` ## psql ```sh psql "postgresql://app:@db.stolondb.com/acme.main" ``` ```sql CREATE TABLE accounts (id int PRIMARY KEY, owner text NOT NULL, balance numeric(10,2) NOT NULL); INSERT INTO accounts VALUES (1, 'ada', 100.00), (2, 'lin', 250.00), (3, 'sam', 75.50); CREATE DATABASE scratch; -- a branch of main: the whole database, copied by reference \c acme.scratch UPDATE accounts SET balance = 0; -- main does not see this \l ``` ## Python with psycopg 3 ```python import psycopg # CREATE DATABASE cannot run inside a transaction block, as in Postgres, # so open the connection that makes a branch with autocommit. with psycopg.connect("postgresql://app:@db.stolondb.com/acme.main", autocommit=True) as conn: print(conn.execute("SELECT id, owner, balance FROM accounts ORDER BY id").fetchall()) conn.execute("CREATE DATABASE py_branch") with psycopg.connect("postgresql://app:@db.stolondb.com/acme.py_branch") as conn: conn.execute("UPDATE accounts SET balance = balance * 2") print(conn.execute("SELECT sum(balance) FROM accounts").fetchone()) ``` ## Python with psycopg2 and SQLAlchemy ```python import psycopg2 conn = psycopg2.connect(host="db.stolondb.com", user="app", password="", dbname="acme.main") cur = conn.cursor() cur.execute("SELECT count(*), sum(balance) FROM accounts") print(cur.fetchone()) conn.close() ``` ```python from sqlalchemy import create_engine, text engine = create_engine("postgresql+psycopg2://app:@db.stolondb.com/acme.py_branch") with engine.connect() as conn: print(conn.execute(text("SELECT sum(balance) FROM accounts")).scalar()) ``` ## Node.js with node-postgres ```js import pg from "pg"; const main = new pg.Client("postgresql://app:@db.stolondb.com/acme.main"); await main.connect(); console.log((await main.query("SELECT id, owner, balance FROM accounts ORDER BY id")).rows); await main.query("CREATE DATABASE node_branch"); await main.end(); const branch = new pg.Client("postgresql://app:@db.stolondb.com/acme.node_branch"); await branch.connect(); await branch.query("UPDATE accounts SET balance = $1 WHERE id = $2", [0, 1]); console.log((await branch.query("SELECT balance FROM accounts WHERE id = 1")).rows); await branch.end(); ``` ## Node.js with postgres.js ```js import postgres from "postgres"; const sql = postgres("postgresql://app:@db.stolondb.com/acme.node_branch"); console.log(await sql`SELECT id, balance FROM accounts WHERE id = ${1}`); await sql.end(); ``` ## Tips - Run `CREATE DATABASE` with autocommit, as with Postgres. - Quote names that are not plain identifiers: `CREATE DATABASE "agent-7"`. - Check your own queries with [Will it run?](https://stolondb.com/compatibility/) --- # Connect a GitHub repository > Install the Stolon GitHub App: every pull request gets its own branch of your database, a check showing what merging it would change, and its data merged when the pull request merges. Source: https://stolondb.com/guides/github/ · Page title: Connect a GitHub repository — Stolon Every pull request gets its own branch of your database. When the pull request merges, so does its data. ## 1. Install the App Open your database in [the console](https://console.stolondb.com/app) and choose **Connect a GitHub repository**. GitHub asks which repository; pick one and you come back linked. ## 2. Open a pull request Its branch is `pr-`, forked from `main`. Point the pull request's preview or tests at it: ```text postgresql://app:@db.stolondb.com/acme.pr-42 ``` The pull request gets one comment naming its branch, and a check, **stolon: data**, showing what merging it would change in the database, with any conflict named by table, row and column. ## 3. Merge it Merging the pull request merges its branch into `main`. Only what the check showed lands: a branch written to after the check is not merged. ## Settings - **Branch from and merge into**: `main`, or any branch. - **When a pull request merges**: merge its data, or leave it. - **Pull requests into**: the repository's default branch, or one you name. - **Drop a pull request's branch when it closes.** No credential is ever posted to GitHub, so public repositories are safe to link. --- # A database branch for every pull request > Give each pull request its own full copy of the database with CREATE DATABASE, run migrations and tests against it, preview the merge with MERGE DATABASE … DRY RUN, then merge or drop it. A shell script for CI. Source: https://stolondb.com/guides/branch-per-pull-request/ · Page title: A database branch for every pull request — Stolon Fork the database when a pull request opens, test against the fork, preview the merge, then merge or drop it. On GitHub, [the Stolon App](https://stolondb.com/guides/github/) does all of this for you; this page is the same flow from any CI. ## The lifecycle | Pull request event | Database | | --- | --- | | opened | `CREATE DATABASE pr_42` while connected to `main` | | pushed to | run migrations and tests with the connection string's database set to `pr_42` | | in review | `MERGE DATABASE pr_42 INTO main DRY RUN` shows what would land and applies nothing | | merged | `MERGE DATABASE pr_42 INTO main`, then `DROP DATABASE pr_42` | | closed | `DROP DATABASE pr_42`; `main` never saw the changes | ## The script Call `pr-branch.sh` from your CI's pull-request events. `STOLON` is the connection string up to the branch name, `postgresql://app:@db.stolondb.com/acme.`; keep it in a CI secret. ```sh #!/bin/sh # usage: pr-branch.sh open|review|merge|close PR_NUMBER set -eu STOLON="${STOLON:?set STOLON in a CI secret}" BR="pr_$2" case "$1" in open) # fork main once; later pushes reuse the branch if ! psql "${STOLON}${BR}" -c "SELECT 1" >/dev/null 2>&1; then psql "${STOLON}main" -c "CREATE DATABASE $BR" fi echo "DATABASE_URL=${STOLON}${BR}" ;; review) # what merging would change; nothing is applied psql "${STOLON}main" -c "MERGE DATABASE $BR INTO main DRY RUN" ;; merge) # atomic: a conflict applies nothing and exits non-zero psql "${STOLON}main" -v ON_ERROR_STOP=1 -c "MERGE DATABASE $BR INTO main" psql "${STOLON}main" -c "DROP DATABASE $BR" ;; close) # abandoned: main never saw it psql "${STOLON}main" -c "DROP DATABASE $BR" ;; esac ``` ## What it looks like ```sh ./pr-branch.sh open 101 psql "postgresql://app:@db.stolondb.com/acme.pr_101" -c "ALTER TABLE accounts ADD COLUMN email text" psql "postgresql://app:@db.stolondb.com/acme.pr_101" -c "INSERT INTO accounts (id, owner, balance, email) VALUES (9, 'zed', 1.00, 'z@example.com')" ./pr-branch.sh review 101 ``` ```text CREATE DATABASE DATABASE_URL=postgresql://app:@db.stolondb.com/acme.pr_101 ALTER TABLE INSERT 0 1 kind | detail ------------------+------------------------------------------------------------------ review | d05632c80632f50dcd9be2164766b7f189d67281f5378343922465d7e70c6f18 schema | ALTER TABLE accounts — ADD COLUMN email rows to apply | 1 deletes to apply | 0 (4 rows) ``` `./pr-branch.sh merge 101` lands the column and the row in one atomic statement. To merge only what was reviewed, see [the review guide](https://stolondb.com/guides/review-agent-changes/). ## Rehearsal or deploy - **Rehearsal:** prove the migration on a full copy, then `close` whatever happens. - **Deploy:** the branch holds only the change (a backfill, a config table), and `merge` is the deploy. --- # Review an agent's changes as a pull request > Let an agent write on its own branch, preview what merging it would change with MERGE DATABASE … DRY RUN and DRY RUN ROWS, settle conflicts with RESOLVE OURS or THEIRS, and merge only what was reviewed with REVIEWED. Source: https://stolondb.com/guides/review-agent-changes/ · Page title: Review an agent's database changes as a pull request — Stolon Give the agent a branch, preview the merge, read it row by row, then land exactly what you reviewed. ## 1. Give the agent its own branch ```sh psql "postgresql://app:@db.stolondb.com/acme.main" -c 'CREATE DATABASE "agent-7"' ``` The agent writes on `agent-7` while `main` keeps taking writes: ```sh psql "postgresql://app:@db.stolondb.com/acme.agent-7" \ -c "UPDATE accounts SET balance = 175.00 WHERE id = 1" \ -c "DELETE FROM accounts WHERE id = 3" \ -c "INSERT INTO accounts VALUES (5, 'noor', 42.00)" psql "postgresql://app:@db.stolondb.com/acme.main" -c "UPDATE accounts SET balance = 130.00 WHERE id = 1" ``` ## 2. Preview the merge ```sh psql "postgresql://app:@db.stolondb.com/acme.main" -c 'MERGE DATABASE "agent-7" INTO main DRY RUN' ``` ```text kind | detail ------------------+------------------------------------------------------------------ conflict | accounts[1].balance: changed here and on agent-7 review | b7a889ecaec843516fb0a1d811e19813bf68076e60c6efbd8a4efcf3eae507f8 rows to apply | 1 deletes to apply | 1 (4 rows) ``` ## 3. Read it row by row ```sh psql "postgresql://app:@db.stolondb.com/acme.main" -c 'MERGE DATABASE "agent-7" INTO main DRY RUN ROWS 10' ``` ```text row | {"after":null,"before":[3,"sam","75.50",null],"change":"removed","changed":[],"key":"3","table":"accounts"} row | {"after":[5,"noor","42.00",null],"before":null,"change":"added","changed":[],"key":"5","table":"accounts"} ``` The console shows the same pull request, with both sides of each conflict. ## 4. Settle conflicts ```sh psql "postgresql://app:@db.stolondb.com/acme.main" -c 'MERGE DATABASE "agent-7" INTO main' ``` ```text ERROR: merge of "agent-7" has 1 conflict(s), nothing applied: accounts[1].balance: changed here and on agent-7 ``` Choose a side with `RESOLVE OURS` (keep `main`'s) or `RESOLVE THEIRS` (take the branch's). ## 5. Merge exactly what you reviewed Pass the preview's digest; if either branch moved since, nothing lands. ```sh MAIN="postgresql://app:@db.stolondb.com/acme.main" DIGEST=$(psql "$MAIN" -tA -c 'MERGE DATABASE "agent-7" INTO main RESOLVE THEIRS DRY RUN' | awk -F'|' '$1=="review"{print $2}') psql "$MAIN" -c "MERGE DATABASE \"agent-7\" INTO main RESOLVE THEIRS REVIEWED '$DIGEST'" ``` ```text action | count ---------------------+------- rows applied | 2 deletes applied | 1 tables created | 0 tables dropped | 0 conflicts resolved | 1 keys renumbered | 0 tables full-scanned | 0 (7 rows) ``` Then `DROP DATABASE "agent-7"`. More in [the docs](https://stolondb.com/docs/). --- # Undo what an agent wrote > Three ways to take back an agent's database writes in Stolon: drop the branch it worked on, read any table as it was with FOR SYSTEM_TIME AS OF, or restore a branch, main included, to a moment. Source: https://stolondb.com/guides/undo-agent-writes/ · Page title: Undo what an agent wrote — Stolon Every past version stays readable, and a branch can be put back to any moment. Cheapest first. ## 1. It worked on its own branch: drop it ```sh psql "postgresql://app:@db.stolondb.com/acme.main" -c 'DROP DATABASE "agent-9"' ``` `main` never saw any of it ([review guide](https://stolondb.com/guides/review-agent-changes/)). ## 2. See what it was before Read any table, on any branch, as it was at a moment: ```sql SELECT * FROM accounts FOR SYSTEM_TIME AS OF '2026-09-26 19:09:27+00' ORDER BY id; ``` Unix seconds work too: `AS OF 1790449767`. ## 3. Put the branch back to a moment In the console's Time Machine, choose **Restore** at the moment. It keeps the present as a branch first, so the restore can be undone; a dropped table comes back with its rows. [The history guide](https://stolondb.com/guides/history/) walks through it. ## 4. On MCP: `checkout` Over [MCP](https://stolondb.com/guides/mcp/), `checkout` to an earlier version is undo; the line it leaves stays readable. --- # Use Stolon as LangGraph's checkpointer > LangGraph's stock PostgresSaver and AsyncPostgresSaver (langgraph-checkpoint-postgres) run against Stolon unchanged. Point them at a branch, and fork every thread's checkpoints with one CREATE DATABASE. Source: https://stolondb.com/guides/langgraph-checkpointer/ · Page title: Use Stolon as LangGraph's Postgres checkpointer LangGraph's stock Postgres checkpointer runs unchanged. Point it at a branch, and fork every thread with one `CREATE DATABASE`. *Run one saver process per checkpoint branch; give each worker process its own branch.* ## Install ```sh pip install langgraph langgraph-checkpoint-postgres "psycopg[binary]" ``` ## Make a branch for it ```sh psql "postgresql://app:@db.stolondb.com/acme.main" -c "CREATE DATABASE agents" ``` ## Use the stock saver ```python import operator from typing import Annotated, TypedDict from langgraph.checkpoint.postgres import PostgresSaver from langgraph.graph import END, START, StateGraph DB_URI = "postgresql://app:@db.stolondb.com/acme.agents" # the database name is the branch class State(TypedDict): steps: Annotated[list, operator.add] builder = StateGraph(State) builder.add_node("plan", lambda state: {"steps": ["plan"]}) builder.add_node("act", lambda state: {"steps": ["act"]}) builder.add_edge(START, "plan") builder.add_edge("plan", "act") builder.add_edge("act", END) with PostgresSaver.from_conn_string(DB_URI) as checkpointer: checkpointer.setup() # creates LangGraph's own tables on this branch graph = builder.compile(checkpointer=checkpointer) config = {"configurable": {"thread_id": "thread-1"}} print(graph.invoke({"steps": []}, config)) print(len(list(graph.get_state_history(config))), "checkpoints") ``` ```text {'steps': ['plan', 'act']} 4 checkpoints ``` `AsyncPostgresSaver` works the same way. ## Fork every thread at once ```python import psycopg with psycopg.connect("postgresql://app:@db.stolondb.com/acme.agents", autocommit=True) as conn: conn.execute("CREATE DATABASE agents_try") with PostgresSaver.from_conn_string("postgresql://app:@db.stolondb.com/acme.agents_try") as cp: print("fork:", builder.compile(checkpointer=cp).invoke({"steps": ["retry"]}, config)) with PostgresSaver.from_conn_string(DB_URI) as cp: print("original:", builder.compile(checkpointer=cp).get_state(config).values) ``` ```text fork: {'steps': ['plan', 'act', 'retry', 'plan', 'act']} original: {'steps': ['plan', 'act']} ``` Try a new prompt or tool across every thread on the copy, then `DROP DATABASE` or [`MERGE DATABASE`](https://stolondb.com/guides/review-agent-changes/). --- # Connect an AI agent over MCP > Connect Claude, ChatGPT, Claude Code or Cursor to your Stolon database: agent memory where every write is a version, undo, history, and review and merge of database branches. Source: https://stolondb.com/guides/mcp/ · Page title: Connect an AI agent over MCP — Stolon Your database serves MCP. In a conversation, an agent can fork the database, query it, change its code, and merge the result, and its memory keeps **every write as a version**, so nothing is lost. ## Connect Your database's MCP address is on its page in [the console](https://console.stolondb.com/app), under **Connect an AI client**: ```text https://console.stolondb.com/mcp/acme ``` Add it to your client and sign in when asked. Each person signs in as themselves, and their agent writes on its own line. | Client | How | | --- | --- | | Claude | Settings, Connectors, **Add custom connector**, paste the address. | | ChatGPT | In Settings, add a custom connector with the address (developer mode). | | Claude Code | `claude mcp add --transport http stolon https://console.stolondb.com/mcp/acme`, then `/mcp` to sign in. | | Cursor | Add `{"mcpServers": {"stolon": {"url": "https://console.stolondb.com/mcp/acme"}}}` to `~/.cursor/mcp.json`. | Clients without sign-in can use a token from the same console panel, sent as `Authorization: Bearer `. ## What an agent can do | Task | Tools | Ask it | | --- | --- | --- | | Fork the database | `create_branch` · `branches` | “Fork the database and try the new pricing there.” | | Query and change data | `sql` | “Which customers signed up last week?” Reads go anywhere; changes belong on a branch. | | Work on the code | `list_files` · `read_file` · `write_file` | “Fix the rounding bug in `billing.py` on that branch.” | | Remember | `put` · `get` · `scan` · `search` | “Save the decisions from this session under `project/`.” | | Look back | `history` · `diff` · `changes` | “What did we believe about the launch date last week, and what changed?” | | Undo | `checkout` | “Go back to before you rewrote the plan.” The newer versions stay readable. | | Correct, with a trail | `put` with `supersedes` | “That price was wrong; correct it.” The old value reads as superseded, not just older. | | Load context | `window` · `brief` | “Load what you need for this task.” Pinned keys come first, under a size budget. | | Check its own citations | `check` | “Check this summary against what we stored.” Stale or missing facts are flagged. | | Try several approaches | `rollouts_open` · `rollouts_close` | “Try three plans in parallel and keep the best.” | | Review database branches | `pull_requests` · `pull_request` · `compare` | “What would merging `agent-7` change?” | | Merge | `merge` · `approve` · `decide` | “Merge it if there are no conflicts, and record why.” | Reads also take `as_of`, a time or a date, to see a past moment. ## A session ```text put {"key": "task/1", "value": "draft plan", "note": "first try"} -> {"version":1} put {"key": "task/1", "value": "wrong plan"} -> {"version":2} checkout {"version": 1} -> {"head":1,"previous_head":2} get {"key": "task/1"} -> {"found":true,"value":"draft plan"} ``` Version 2 is still readable: undo erases nothing. --- # Read, branch, compare and restore a past moment > Work with a Stolon database's history: read a table at a past moment with FOR SYSTEM_TIME AS OF, branch from that moment, compare it with now using COMPARE DATABASE, and restore a branch to it while keeping the present as a branch. Source: https://stolondb.com/guides/history/ · Page title: Read, branch, compare and restore a past moment — Stolon Read a past moment, compare it with now, branch from it, and go back to it while keeping the present. ## 0. A table, a moment, and some changes ```sh psql "postgresql://app:@db.stolondb.com/acme.main" ``` ```sql CREATE TABLE customers (id int PRIMARY KEY, name text, plan text, credit numeric(10,2)); INSERT INTO customers VALUES (1, 'ada', 'pro', 120.00), (2, 'grace', 'free', 0.00), (3, 'linus', 'pro', 80.50); ``` Note the moment: ```sh date -u '+%Y-%m-%d %H:%M:%S+00' ``` ```text 2026-09-28 20:07:25+00 ``` Then change things, the way an agent or a bad migration would: ```sql UPDATE customers SET credit = 175.00 WHERE id = 1; UPDATE customers SET plan = 'pro' WHERE id = 2; DELETE FROM customers WHERE id = 3; INSERT INTO customers VALUES (4, 'barbara', 'free', 10.00); ``` ## 1. Read the past moment ```sql SELECT * FROM customers FOR SYSTEM_TIME AS OF '2026-09-28 20:07:25+00' ORDER BY id; ``` ```text id | name | plan | credit ----+-------+------+-------- 1 | ada | pro | 120.00 2 | grace | free | 0.00 3 | linus | pro | 80.50 (3 rows) ``` Any table, any branch. The console's Time Machine scrolls a table back the same way. ## 2. Compare it with now ```sql COMPARE DATABASE main AS OF '2026-09-28 20:07:25+00' WITH main CELLS; ``` ```text section | table | item | change | added | removed | modified | cells | a | b | cursor ---------+-----------+-----------------------+----------+-------+---------+----------+-------+--------+----------------------------------------+--------------------------------------------- cell | customers | id=1: credit | modified | | | | | 120.00 | 175.00 | 2-6.0.637573746f6d657273.018000000000000001 cell | customers | id=2: plan | modified | | | | | free | pro | 2-6.0.637573746f6d657273.018000000000000002 ``` `a` is the value then, `b` the value now. Drop `CELLS` for counts per table, or use `ROWS`. Either side can be a branch, a moment (`AS OF`) or a commit (`AT DEPTH n`); `TABLE t` narrows it. The console's Compare page and the MCP `compare` tool give the same answer. ## 3. Branch from the moment In the console's Time Machine, choose *Branch from this moment*, here named `before-cleanup`, and connect to it: ```sh psql "postgresql://app:@db.stolondb.com/acme.before-cleanup" -c 'SELECT * FROM customers ORDER BY id' ``` ```text id | name | plan | credit ----+-------+------+-------- 1 | ada | pro | 120.00 2 | grace | free | 0.00 3 | linus | pro | 80.50 (3 rows) ``` ## 4. Go back, and keep the present In Time Machine, choose **Restore** at the moment. The console keeps the present as a branch (`main-before-restore-`), then puts `main` back: ```sql SELECT * FROM customers ORDER BY id; ``` ```text id | name | plan | credit ----+-------+------+-------- 1 | ada | pro | 120.00 2 | grace | free | 0.00 3 | linus | pro | 80.50 (3 rows) ``` The present is on the kept branch: ```text id | name | plan | credit ----+---------+------+-------- 1 | ada | pro | 175.00 2 | grace | pro | 0.00 4 | barbara | free | 10.00 (3 rows) ``` To undo the restore, the console merges the kept branch back into `main` (`MERGE DATABASE`). --- # Stolon compared > Dated, sourced comparisons of Stolon with Neon, Supabase and Dolt on branching, merging, history and pricing: based on each vendor's own pages, as of 26 September 2026. Source: https://stolondb.com/compare/ · Page title: Stolon compared with Neon, Supabase and Dolt Branching, merging and cost, side by side, from each vendor's own pages. - [Stolon and Neon](https://stolondb.com/compare/neon/). A Neon branch runs its own compute; a Stolon branch merges back. - [Stolon and Supabase](https://stolondb.com/compare/supabase/). A Supabase branch starts without data; a Stolon branch starts with the whole database. - [Stolon and Dolt](https://stolondb.com/compare/dolt/). Both branch and merge data. *Vendor facts as of 26 September 2026, each linked to its source. Check their current pages before you decide.* --- # Stolon and Neon > Stolon and Neon side by side, based on Neon's own pages, as of 26 September 2026: branching, merging, restore and prices. Source: https://stolondb.com/compare/neon/ · Page title: Stolon vs Neon: branching, merging and pricing compared Both give a Postgres client an instant branch. A Neon branch gets its own compute; a Stolon branch merges back. *As of 26 September 2026.* | | Neon | Stolon | | --- | --- | --- | | What it is | open-source serverless Postgres; storage separated from compute (Apache-2.0) | a Postgres-compatible database; closed source | | A branch | a copy-on-write clone of the parent's data; each branch has dedicated compute | `CREATE DATABASE b`: instant at any size; the database name selects it | | Merging a branch back | Neon's branching overview describes reset-from-parent and restore; it does not describe merging a branch's data into its parent | `MERGE DATABASE b INTO main`, with conflicts named `table[pk].column` and a `DRY RUN` preview | | Going back in time | instant restore within the history window: 6 hours on Free (1 GB limit), up to 7 days on Launch, up to 30 on Scale | `FOR SYSTEM_TIME AS OF` on any table and branch, and restore a branch to a moment | | Branch price | 10 branches per project included on Free and Launch, 25 on Scale; then $1.50 per branch-month, prorated hourly | no per-branch fee on paid plans | | Compute | $0.106 per CU-hour on Launch, $0.222 on Scale; Free includes 100 CU-hours per project; scales to zero after 5 minutes idle on Free and Launch | no per-branch compute | | Storage | $0.35 per GB-month on Launch and Scale; 0.5 GB per project on Free; instant-restore history $0.20 per GB-month | free in preview; prices published at launch | | Postgres surface | PostgreSQL itself, including extensions | Postgres-compatible, with pgvector and the common extensions ([check your queries](https://stolondb.com/compatibility/)) | ## When each fits - **Neon** if you want each branch to be a Postgres instance with its own compute. - **Stolon** if you want a branch per agent, test or pull request, with changes coming back to `main` as a reviewed merge. ## Sources - [neon.com/pricing](https://neon.com/pricing): plans, branch, compute, storage and restore prices - [neon.com/docs/introduction/branching](https://neon.com/docs/introduction/branching): what a branch is, reset from parent, instant restore - [github.com/neondatabase/neon](https://github.com/neondatabase/neon): description and license - Stolon: [docs](https://stolondb.com/docs/) --- # Stolon and Supabase > Stolon and Supabase side by side, based on Supabase's own pages, as of 26 September 2026: branching, merging, recovery and prices. Source: https://stolondb.com/compare/supabase/ · Page title: Stolon vs Supabase: branching, merging and pricing compared Supabase is a platform around Postgres, and its branches are environments for schema changes. A Stolon branch carries the whole database, and its data merges back. *As of 26 September 2026.* | | Supabase | Stolon | | --- | --- | --- | | What it is | a Postgres development platform: a dedicated Postgres plus auth, storage, realtime and generated APIs (Apache-2.0) | a Postgres-compatible database; closed source | | A branch | a separate environment with its own instance and API credentials; by default it starts with no data from the main project (seed files, or an "include data" option) | `CREATE DATABASE b`: the whole database, schema, rows and history, instantly | | Merging a branch back | merging runs a deployment workflow that applies the branch's pending migrations to production; the branching guide describes no data merge | `MERGE DATABASE b INTO main`: rows and schema, with conflicts named `table[pk].column` | | Going back in time | daily backups kept 7 days on Pro, 14 on Team; point-in-time recovery $100 per month per 7 days of retention | `FOR SYSTEM_TIME AS OF` on any table and branch, and restore a branch to a moment | | Branch price | $0.01344 per branch, per hour | no per-branch fee on paid plans | | Plans | Free $0 (2 active projects, 500 MB database, paused after a week idle); Pro $25/month (8 GB disk included, then $0.125 per GB); Team $599/month; Enterprise custom | free in preview; prices published at launch | | Postgres surface | PostgreSQL itself, with extensions | Postgres-compatible, with pgvector and the common extensions ([check your queries](https://stolondb.com/compatibility/)) | ## When each fits - **Supabase** if you want the platform (auth, storage, realtime and APIs) with branches as preview environments. - **Stolon** if what you branch is the data: an agent's writes, a backfill or a migration, merged back after review. ## Sources - [supabase.com/pricing](https://supabase.com/pricing): plans, branching, disk, backups and PITR prices - [supabase.com/docs/guides/deployment/branching](https://supabase.com/docs/guides/deployment/branching): what a branch is, its data, how it merges - [github.com/supabase/supabase](https://github.com/supabase/supabase): description and license - Stolon: [docs](https://stolondb.com/docs/) --- # Stolon and Dolt > Stolon and Dolt/Doltgres side by side, based on DoltHub's own pages, as of 26 September 2026: branching and merging data, compatibility, license and hosted prices. Source: https://stolondb.com/compare/dolt/ · Page title: Stolon vs Dolt and Doltgres: version-controlled databases compared Dolt is the nearest peer: a SQL database that branches, diffs and merges data the way git handles code. Stolon does it behind the Postgres wire protocol. *As of 26 September 2026.* | | Dolt / Doltgres | Stolon | | --- | --- | --- | | What it is | a SQL database you can fork, clone, branch, merge, push and pull like a git repository; Dolt is MySQL-compatible, Doltgres Postgres-compatible (both Apache-2.0) | a Postgres-compatible database with branch and merge as SQL statements; closed source | | Branch, diff, merge | exposed in SQL through system tables, functions and procedures; also push and pull between copies | `CREATE DATABASE`, `MERGE DATABASE … [DRY RUN]`, `FOR SYSTEM_TIME AS OF` | | Beside the rows | (not compared here) | a branch also carries code references, such as a git SHA, and an agent's recorded decisions | | Hosted price | Hosted Dolt: a trial instance at $50/month (t2.medium, 50 GB); other instance prices at hosted.doltdb.com/pricing. DoltHub Pro: $5/month up to 5 GB of private data, then $1/GB-month | no per-branch fee on paid plans; prices published at launch | | Self-hosted | open source; run it anywhere | a single-tenant binary | ## When each fits - **Dolt** if you want open source, git-style push and pull between copies, or MySQL compatibility. - **Stolon** if you want Postgres clients, history you can query at any moment, and merges reviewed before they land. ## Sources - [github.com/dolthub/dolt](https://github.com/dolthub/dolt): description, license, SQL interface - [github.com/dolthub/doltgresql](https://github.com/dolthub/doltgresql): description and license - [Hosted Dolt: notable features](https://www.dolthub.com/docs/products/hosted/notable-features/): the $50 trial instance - [DoltHub Pro for $5/month](https://www.dolthub.com/blog/2026-04-24-announcing-dolthub-pro-for-5-dollars-per-month/): DoltHub pricing - [hosted.doltdb.com/pricing](https://hosted.doltdb.com/pricing): hosted Dolt's live price list --- # Blog > Writing from the Stolon team on versioned databases, branching and building with AI agents. Source: https://stolondb.com/blog/ · Page title: Blog — Stolon Notes on versioned databases and building with agents. - [What is a fully persistent B-tree?](https://stolondb.com/blog/fully-persistent-b-tree/) --- # What is a fully persistent B-tree? > A fully persistent B-tree keeps every version readable and lets any version start a new one. What the term means, and what it buys a database. Source: https://stolondb.com/blog/fully-persistent-b-tree/ · Page title: What is a fully persistent B-tree? — Stolon A B-tree in which every version stays readable and any version can start a new one, so its versions form a tree. Stolon is built on one, which is why a branch copies nothing and reads stay flat as branches get deeper and more numerous. ## The definition The terms come from the data-structures literature, starting with [Driscoll, Sarnak, Sleator and Tarjan (1989)](https://www.cs.cmu.edu/~sleator/papers/another-persistence.pdf). A structure is *persistent* when a change makes a new version and leaves the old one readable. What differs is which versions can change: | | Readable | Changeable | History is | | --- | --- | --- | --- | | Ephemeral | the current version | the current version | not kept | | Partially persistent | every version | the newest | a line | | Fully persistent | every version | any version | a tree | | Confluent | every version | any version, and two can be combined into one | a graph | ## What it buys a database - **Branching copies no data.** Each branch added 489 bytes and no data pages. - **Branch count and depth leave read cost unchanged.** Reads are flat across 125 levels of branch depth, and a read scans 2,100 entries and 16 pages at 100, 1,000 and 10,000 live branches. - **Any version is a starting point.** Read a table at a past moment, branch from it, compare it with now, or put a branch back to it ([the history guide](https://stolondb.com/guides/history/)). ## Three objections to building one on disk Each has an answer, and Stolon is built on it. - **Nodes that outgrow a page.** Stolon's pages never grow, and large values are stored in chunks. - **Chasing pointers between versions.** A read walks from the root to a leaf, as in any B-tree. Nothing follows pointers from version to version. - **Reclaiming space.** Dropped branches and expired history are reclaimed automatically, and the file shrinks to about what it still holds, without stalling the database. - [How it works](https://stolondb.com/how-it-works/) — The engine, branches, merge, durability and measurements. - [Read and restore a past moment](https://stolondb.com/guides/history/) — Use any version as a starting point. --- # Pay for what your agents do. > Plans by who they are for (Free, Team, Agents and Enterprise), metered on throughput and storage held, with no per-branch fees on paid plans and a history window of 24 hours, 7 days or 30 days. Pricing is published at launch. Source: https://stolondb.com/pricing/ · Page title: Pricing — Stolon Metered on throughput and storage held. No per-branch fees on paid plans. [Start free](https://stolondb.com/signup) [Read the docs](https://stolondb.com/docs/) *Free while in preview. Pricing is published at launch.* ### Throughput The statements and writes you run. ### Storage held What your databases keep now, history included. ### No per-branch fees Give every agent, test or migration a branch; the bill doesn't change. ## Plans | | Free | Team | Agents | Enterprise | | --- | --- | --- | --- | --- | | For | trying it | app teams and early agent work | agent fleets in production | regulated and large organizations | | Databases | 1 | several | many | by contract | | Branches | up to 10 live | no per-branch fee | no per-branch fee | no per-branch fee | | History window | 24 hours | 7 days | 30 days | longer, by contract | | Throughput and storage | an included allowance; past it, work slows down rather than failing | included, then metered | included, then metered | by contract | | Branch, compare, restore, Time Machine | yes | yes | yes | yes | | MCP server for agents | yes | yes | yes | yes | | Review and merge: branch policy, protected branches, approvals | — | yes | yes | yes | | Provenance, checks and watchpoints | — | — | yes | yes | | Roles, grants and row-level security; a minimum history-retention policy; a single-tenant deployment you run | — | — | — | yes | | Price | free | published at launch | | | ### Provisioned production databases coming For production application databases, alongside Team and above A reserved size at a flat monthly price, with automatic failover and an uptime commitment. ## No cold starts, and nothing to size No instance size to choose. An idle database stays running, and idle time isn't billed. ## What a history window promises Inside the window you can read any table at a past moment, branch from it, or compare it with another state. Kept history counts toward storage held. Name a database and you get a connection string. Enterprise on request. [Start free](https://stolondb.com/signup)