PocketBase

Open-source backend in a single file

Self-Hosting Platforms (PaaS) ★ 61.1k stars Easy setup MIT

PocketBase is an open-source backend that bundles an embedded SQLite database, realtime subscriptions, authentication and a file storage API into one portable executable. It is self-hosted as a single binary.

Key features

  • Single executable backend
  • Embedded SQLite
  • Realtime subscriptions
  • Built-in admin UI

Pros & cons

Strengths

  • Single portable binary
  • Realtime subscriptions built in
  • Admin UI included

Trade-offs

  • SQLite limits scale
  • No horizontal scaling
  • Still pre-1.0

PocketBase replaces

Last reviewed Aug 26, 2026 · 998 words

A PocketBase deployment is one executable, one data folder, and one port. That is the entire operational surface: no database server, no cache, no queue, no Docker unless you insist. On the cheapest VPS a host will sell you, about $4 a month for 1 vCPU and 512 MB, it serves authentication, a REST and realtime API, file uploads, and an admin dashboard with room to spare; the catalogue's 64 MB RAM floor is not a typo. The catch is printed on the tin. Everything lives in SQLite on one machine, so the question is never whether PocketBase is easy (it is) but whether your app will ever need a second server. Most side projects and internal tools never do, and for those it is the best backend-in-a-box I have used.

Working API in 10 minutes, no code

Download the archive for your platform from pocketbase.io, unzip it, and start it:

./pocketbase serve --http=0.0.0.0:8090

Open http://your-host:8090/_/ and create the first superuser. From there the dashboard does what a week of Express boilerplate would: create a collection, add typed fields (text, number, relation, file, JSON), and the CRUD endpoints exist immediately at /api/collections/posts/records. Auth collections give you email and password plus OAuth2 providers (Google, GitHub, Apple, and about 20 more) with the token handling done for you.

The part that makes this a real product rather than a toy is the API rules. Each collection has 5 rule slots (list, view, create, update, delete), each a filter expression such as @request.auth.id = author.id, evaluated per request. Get them right and you have a multi-tenant backend without a line of server code. Get them wrong and you leak data, so know the two extremes: an empty rule means public access, and the locked rule means superusers only. New collections default to locked. Leave them that way until you have written a rule on purpose.

Realtime is a Server-Sent Events stream at /api/realtime. The JavaScript SDK wraps it in one call, pb.collection('posts').subscribe('*', callback), and the same API rules filter what each subscriber receives.

Run it under systemd, behind Caddy

Bind PocketBase to localhost and let a reverse proxy handle TLS:

[Unit]
Description=PocketBase
After=network.target

[Service]
User=pocketbase
WorkingDirectory=/opt/pocketbase
ExecStart=/opt/pocketbase/pocketbase serve --http=127.0.0.1:8090
Restart=always
LimitNOFILE=4096

[Install]
WantedBy=multi-user.target

A 2-line Caddy site block in front of that gives you a certificate and HTTP/2. PocketBase can also fetch its own Let's Encrypt certificate if you run serve yourdomain.com on ports 80 and 443, which is fine for a box that runs nothing else. There is no official Docker image; the docs publish a 10-line Alpine Dockerfile, and the only thing worth a volume is pb_data.

Everything is in pb_data, and the backup button is real

pb_data/data.db is the SQLite file (WAL mode, so you will also see -wal and -shm files), pb_data/storage/ holds uploaded files unless you point uploads at an S3 bucket, and auxiliary.db holds request logs you can delete without regret. Never copy the live data.db with cp; a WAL database copied mid-write restores as corruption.

Instead use the built-in backups under Settings → Backups. It produces a zip of pb_data, runs on a cron expression you set, and uploads to any S3-compatible bucket. Restore is a button on the same page, and it works, but do one test restore into a scratch instance before you rely on it. If you prefer your own tooling, sqlite3 pb_data/data.db ".backup /backups/pb.db" plus a tar of storage/ is equivalent.

Extend with JS hooks before you reach for a framework

Drop *.pb.js files in pb_hooks/ and PocketBase runs them in an embedded JavaScript runtime on startup. Hooks fire on record events (validate a field, send an email after signup, deny a delete), on a schedule via cronAdd, and on custom routes via routerAdd. It is enough for the 90% of backend logic that is "check something, then write something". The remaining 10% is why the Go path exists: import PocketBase as a library, write handlers in Go, ship one binary that is your whole app. Schema changes made in the dashboard are recorded as migration files in pb_migrations, which is how you promote a dev schema to production without clicking through it twice.

Where SQLite actually stops

Reads are absurdly fast because there is no network hop; thousands of requests per second on a $4 VPS is normal. Writes are serialised, one at a time, which is fine for a form, a SaaS with 500 customers, or a game leaderboard, and not fine for telemetry ingest at thousands of writes a second. There is no horizontal scaling and no read replica; your ceiling is one machine, and your availability is that machine's availability. The pre-1.0 status matters too: breaking changes between minor versions happen, and the release notes tell you what to run, so read them before pulling.

When those limits are real for you, the answer is Postgres-backed platforms. PocketBase vs Supabase covers the usual jump, and Appwrite vs PocketBase covers the other direction. If you are leaving Google's platform, the Firebase alternatives page ranks the options.

What I'd do

PocketBase on a $4 VPS, systemd unit as above, Caddy in front, superuser login on a long random password, every collection locked until it has a deliberate rule. Nightly backups to a B2 bucket from the Settings page, one test restore before launch. Write logic in pb_hooks and switch to the Go build only when a hook file passes 300 lines. For anything under 100,000 users and a normal write rate, I would not look elsewhere.

Compare PocketBase

3 head-to-head comparisons.

Similar self-hosting platforms (paas) apps