Chelabase

Manage, collaborate, iterate. On Postgres.

An open-source Postgres platform you can run yourself. Branch, merge and restore databases, give your team access Postgres itself enforces, and query from your app with a typed client. Its core services are written in Rust.

AlphaNot ready for production data yet: expect breaking changes, and report what breaks.

Illustration, not your databases.

Run it on your machine.

  1. Clone and configure

    Copy .env.example to .env. The defaults run on one machine.

  2. Start it

    docker compose up -d --wait. You need Docker Engine 26 and Compose 2.30 or newer, and room for about 26 containers.

  3. Claim it

    Read the setup code from the logs and create the first account with it: that account is the instance's admin.

  4. Create a database

    Open Studio, add a database, branch it and query it.

Your terminalInstall
git clone https://github.com/chelabase/chelabase.git
cd chelabase/infra/compose
cp .env.example .env
docker compose up -d --wait
docker compose logs init-secrets # your setup code

# want a populated demo instead? on a fresh stack:
# docker compose -f docker-compose.yml -f docker-compose.example.yml up -d --wait
# then open http://studio.chelabase.localhost:8000

Everything in one place.

Chelabase's core services are built in Rust, and so is Neon's storage engine under Postgres. Accounts live in a small internal Identity service on Better Auth. It all runs together on one machine.

The crab is a nod to Ferris, Rust's mascot. Chela is Greek for claw.

How it compares.

What each platform offers today, from its own docs. Benchmarks come later.

Comparison preview — benchmarks coming later

Comparison preview
ChelabaseSupabaseFirebaseNeonPlanetScale PostgresPlanetScale MySQL
PostgresYesYesYesYesYesMySQL
Copy-on-write branchesYesSchema-only branchesNoYesNoNo
Schema merge between branchesYesPartlyNoNoNoYes
Protected branchesYesNoNoYesPartlyYes
Point-in-time restoreYesYesYesYesYesNo
Self-hostableYesPartlyNoPartlyNoNo
Team access enforced by PostgresYesDashboard rolesCloud IAMOrg rolesOrg rolesOrg roles
Typed query APIYesYesYesYesNoNo
App-user auth, with SSRYesYesYesYesNoNo
Table and SQL editorsYesYesPartlyYesPartlyPartly
Live rows in the editorYesNoYesNoNoNo
Realtime for your appComing soonYesYesYesNoNo
Object storageYesYesYesYesNoNo

From each product's docs, November 2026. Neon's realtime and object storage are in beta; Neon's schema diff compares branches but doesn't merge them. Supabase merges a branch into production through a schema diff, and self-hosted Supabase runs one project without branching or point-in-time restore. PlanetScale merges schema through deploy requests on MySQL (Vitess) only. Firebase's Postgres is SQL Connect (Cloud SQL for PostgreSQL, with typed SDKs). Neon's storage engine is open source, but its control plane isn't.

Manage it from one console.

Studio holds the whole database: tables, SQL, roles, keys and your app's users. A change shows as the SQL it will run, before it runs.

  • Structure changes you can read first

    The table editor stages column, index and constraint changes, shows them as the exact SQL with a dry run, and applies them in one transaction.

  • A SQL editor with a guard

    It asks before risky statements, runs as the owner or as a role you pick, and keeps saved queries per database, shared with the project, with your run history in your browser.

  • Credentials you can see again

    Login role passwords are encrypted at rest and can be revealed later, so a lost connection string doesn't mean a reset.

  • Security in plain view

    Studio flags tables the data API can reach without row-level security, and says when you're running as the owner.

A staged change shows its SQL and a dry run before anything runs.
Studio's table editor on sales.orders, Structure tab. A new column, shipped_at timestamptz, is staged in the Pending changes panel with its ALTER TABLE statement and a passed dry run.

Bring your team in.

Invite people, group them into teams, and grant each team the Postgres roles it may act as. Postgres' own privileges decide the rest, so a schema can belong to one team.

  • Teams with live grants

    Change a team's grant and every member changes with it. Per-database overrides narrow it for one person.

  • Protected branches

    Protect a branch from delete and reset. Protecting first reviews any code an untrusted role could run in an Admin's session.

  • Work side by side

    The table editor shows live rows and who else is looking, and a save fails rather than overwrite someone's change.

  • An access log

    Every invite, grant, approval and removal is recorded with who did it and what changed, never secrets.

The Finance team holds Developer on Acme, acting as finance: one grant for all its members.
Studio's Finance team page, Project access card for Acme: platform role Developer, acting as the Postgres role finance, with engineering, sales and support left unchecked.

Build your app on a typed API.

One endpoint, POST /data/v1/query, and a client with types fetched from your schema. Public-key queries run as anon or authenticated, so row-level security decides what each user sees. The client isn't on npm yet: use it from the repository.

  • Auth for your app's users

    Sign-up, sign-in and sessions, with helpers for row-level security policies.

  • Server rendering

    Browser and server clients see the same signed-in user through cookies, and the refresh token stays HttpOnly.

  • Plain Postgres too

    Migrations, ORMs and psql connect over the Postgres protocol with a login role.

Your server, with @chelabase/clientorders.ts
import { createServerClient } from "@chelabase/client/server";
import { type Database, types } from "./db";
// ./db comes from GET /data/v1/types

const db = createServerClient<Database>({ url, key, types, cookies });
const user = await db.auth.getUser();

const mine = await db
  .from("orders")
  .select("id", "total")
  .where({ customer_id: user.id });
// sales.orders, only the signed-in customer's rows

Branch it. Reset it. Restore it. Merge it.

Every database starts with one branch, main. Try a change on a copy of real data, then bring it home.

Tide gauge: main's last 7 daysIllustration, not live data
What happens

Branch

Copy any branch as it is now, or as it was at any point in its history window (seven days by default). The copy is copy-on-write, so no data is copied: it's ready as soon as its compute starts, with its own endpoint and password.

preview is a copy-on-write copy of main as it was 3 days ago. It shares main's pages until either side writes.

Protected main, and feature-discounts branched from it, ready to merge.
Studio's branches list for the Acme database: main, protected, and feature-discounts, branched from main, each with its endpoint and actions such as Reset to parent, Restore and Merge into main.

Start with the Quickstart.

Create a database, add a table, and query it from your app with the typed client.