Your whole backend,
built on PostgreSQL.
Collections, a REST and realtime API, auth, files, hooks and an admin dashboard, in one Rust binary. Every collection is a real PostgreSQL table, and every server you add shares it.
$ mkdir slonbase && cd slonbase $ curl -fsSLO https://raw.githubusercontent.com/ayeshrodz/slonbase/main/compose.yaml $ echo "POSTGRES_PASSWORD=$(openssl rand -hex 24)" > .env $ docker compose up -d $ docker compose logs slonbase | grep "setup?token" # open the link
Starts slonbase and PostgreSQL 17. The dashboard is at localhost:8090/_/, the API at /api/.
A few lines of JavaScript against the API, and the dashboard's grid updating live as realtime events arrive.
A new dashboard.
Faster everywhere else.
The biggest release since 1.0: a redesigned dashboard, writes that no longer queue behind each other, compressed answers, live previews for view collections, and every release checked against PocketBase itself.
Redesigned from the sidebar up
One sidebar for sections, collections, theme and account. A warm, muted palette in light and dark, pill tabs, a calmer records grid, records edited in a drawer beside the list, and an overview with the day's traffic.

Commits no longer wait in line
Realtime no longer sends a notification inside every write, which made PostgreSQL commit them one at a time.
Compressed answers
gzip for JSON over 1 KB. A 30-record page drops from 14.5 KB to 2.2 KB, for about 25 µs of CPU. Anything carrying a token stays uncompressed, so BREACH can't guess it.
See a view before you save it
The view editor shows the fields and the first rows of your query as you type, through POST /api/collections/meta/dry-run-view, run read-only and time-limited.
SELECT p.id, p.title, count(c.id) AS comments
FROM posts p LEFT JOIN comments c ON c.post = p.id
GROUP BY p.id -- fields: id · title · comments (number)
Checked against PocketBase, every push
A differential runner starts PocketBase and slonbase side by side, sends both the same requests, plus a thousand fuzzed HTML documents for excerpts, and fails CI on any difference in the answers.
A backend in minutes.
Your data where it belongs.
Define collections in a dashboard and get a REST API, auth, realtime and files right away, with every table a real PostgreSQL table you can query, replicate and back up.
Auth and access rules
Password, OAuth2, one-time password and MFA sign-in, email flows, and per-collection API rules in one small filter language, compiled to SQL your indexes can use.
Real PostgreSQL tables
Each collection is a table in the slonbase schema. Query it with SQL, replicate it, pg_dump it, or run it on a managed service.
Realtime for every change
A trigger on each table announces every write, whoever makes it: the API, SQL, auth flows or another program. Subscribers see it, with their rules applied.
Scales out
Run several instances on one database behind any load balancer. Realtime, schema changes, settings and rate limits are shared through LISTEN/NOTIFY. No sticky sessions.
Extend it your way
JavaScript hooks for requests, records, realtime, files and mail, plus routes, cron jobs, migrations and a query builder. Or embed it as a Rust library.
Operations built in
Rate limits, request logs, scheduled backups to S3, Prometheus metrics, projects on one server, and upgrades tested from the first release.
Write less backend.
Ship the app.
A typed client SDK, a filter language your rules and queries share, hooks for the logic that's yours, and SQL whenever you want it. Use the PocketBase SDKs you may already know: they work with slonbase's API.
- Filters and API rules, relation paths,
@request.*and@collection.* - Auth with passwords, OAuth2 providers, one-time passwords and MFA
- Batch requests in one transaction,
expand, files and thumbnails - Clear, field-level validation errors your forms can show as they are
import PocketBase from "pocketbase"; // the PocketBase JS SDK works with slonbase's API const pb = new PocketBase("http://localhost:8090"); await pb.collection("users") .authWithPassword("ann@example.com", "secret"); const posts = await pb.collection("posts").getList(1, 20, { filter: 'published = true && views > 100', expand: "author", }); // realtime pb.collection("posts").subscribe("*", (e) => { console.log(e.action, e.record.title); });
// hooks: your logic, next to your data onRecordCreateRequest((e) => { if (!e.auth) throw new ForbiddenError("Sign in first."); e.record.set("author", e.auth.id); e.next(); }, "posts"); routerAdd("GET", "/api/top", (e) => { const rows = arrayOf(new DynamicModel({ title: "", views: 0 })); $app.db().select("title", "views").from("posts") .where($dbx.hashExp({ published: true })) .orderBy("views DESC").limit(10).all(rows); return e.json(200, rows); }); cronAdd("cleanup", "0 3 * * *", () => { $app.db().delete("posts", $dbx.hashExp({ status: "spam" })).execute(); });
-- every collection is a real table: query it, join it, index it SELECT a.name, count(*) AS posts, sum(p.views) AS views FROM slonbase.posts p JOIN slonbase.users a ON a.id = p.author WHERE p.published GROUP BY a.name ORDER BY views DESC; -- and changes made here reach realtime subscribers too UPDATE slonbase.posts SET featured = true WHERE views > 10000;
Fast where it matters.
Built in Rust with tokio and axum. Filters compile to parameterized SQL, and PostgreSQL's planner uses your indexes. The same seeded data and workloads, on the same machine, through the same HTTP API.
A dashboard you'll enjoy.
Live grids, a schema editor, API rules, logs and an SQL console. It follows your light or dark theme, works on phones, and ⌘K jumps anywhere.
One database.
Many servers.
Put several slonbase instances behind any load balancer. They share everything through PostgreSQL, so you scale the stateless part and keep one source of truth.
- Realtime events reach subscribers on every instance, and subscriptions find their client's instance: no sticky sessions
- Schema changes, settings and backup restores reload everywhere
- Rate limits count across instances, cron jobs run once per schedule
- Prometheus metrics on a private port: requests, latency, pool use, realtime
Inspired by PocketBase.
Built from scratch.
PocketBase showed how good a backend in one binary can feel. slonbase is a new project, written in Rust for PostgreSQL, that keeps its API compatible, so your SDK code, hooks and migrations carry over. Here's how the two differ.
| slonbase | PocketBase | |
|---|---|---|
| Database | PostgreSQL 14+ (yours, or managed) | SQLite, inside the process |
| API and SDKs | Its own API, compatible with the PocketBase SDKs | The PocketBase SDKs |
| Extending | JavaScript hooks (PocketBase's run as they are), or Rust | JavaScript hooks, or Go |
| Instances | Any number on one database, behind any load balancer | One |
| Your data | Real tables: SQL, replicas, pg_dump, BI tools | A SQLite file |
| Realtime | Every change, including SQL and other programs | Changes made through the app |
| Moving parts | One binary and a PostgreSQL server | One binary |
PocketBase is the better choice when…
- you want zero moving parts: one file, SQLite inside;
- one small app on one small machine is the whole plan (in-process SQLite answers a single client's lookups faster);
- you extend it in Go.
The latest release.
A release that builds once and ships sooner: the packages are built a single time, CI shares one build between its jobs, and the apt and dnf repositories keep the five newest versions. The same binary as 2.1.2, with the dashboard that tells its parts apart.
Release notes →- Faster releases: packages built once (2.1.3)
- Layered surfaces and accent-coloured controls (2.1.2)
- A dashboard that stays usable during bulk imports (2.1.1)
- Lockout after failed sign-ins (2.1)
- A rate-limit tester (2.1)
- Roles for superusers, and API keys (2.0)
- An email designer with a live preview (2.0)
Install it your way.
slonbase connects to any PostgreSQL 14+ server. Finish with the setup wizard, or with slonbase setup.
mkdir slonbase && cd slonbase curl -fsSLO https://raw.githubusercontent.com/ayeshrodz/slonbase/main/compose.yaml echo "POSTGRES_PASSWORD=$(openssl rand -hex 24)" > .env docker compose up -d docker compose logs slonbase | grep "setup?token"
curl -fsSL https://ayeshrodz.github.io/slonbase/slonbase.gpg | sudo tee /usr/share/keyrings/slonbase.gpg > /dev/null curl -fsSL https://ayeshrodz.github.io/slonbase/slonbase.list | sudo tee /etc/apt/sources.list.d/slonbase.list sudo apt update && sudo apt install slonbase sudo journalctl -u slonbase | grep "setup?token"
sudo curl -fsSL -o /etc/yum.repos.d/slonbase.repo https://ayeshrodz.github.io/slonbase/slonbase.repo sudo dnf install slonbase sudo journalctl -u slonbase | grep "setup?token"
curl -fsSLO https://github.com/ayeshrodz/slonbase/releases/download/v2.1.3/slonbase-2.1.3-linux-amd64.tar.gz tar xzf slonbase-2.1.3-linux-amd64.tar.gz ./slonbase serve # prints the setup link
# collections, records, password hashes, files and settings, from pb_data or a backup zip slonbase setup --database-url "postgres://..." --email you@example.com --password '...' slonbase import-pocketbase ./pb_data cp pb_hooks/*.pb.js slonbase_hooks/ # your hooks keep working slonbase serve
Or deploy with one click on Render, or with the setups for Fly.io and others. Packages update with apt upgrade and dnf upgrade (repository details).
The story behind slonbase
Why build a new backend for PostgreSQL from scratch, and how it's tested to behave the way apps expect. Read the story on the blog.