DEV Community

Cover image for PocketBase: The Open-Source Firebase Alternative That Runs in a Single Go Binary
Syed Anzar
Syed Anzar

Posted on

PocketBase: The Open-Source Firebase Alternative That Runs in a Single Go Binary

PocketBase: The Open-Source Firebase Alternative That Runs in a Single Go Binary

You've built a side project. It needs a backend. You don't want to set up PostgreSQL, configure Redis, write auth from scratch, wrestle with Docker Compose, or pay Firebase prices when your user count grows.

What if the entire backend - database, realtime subscriptions, authentication, file storage, and an admin dashboard - was a single 15 MB Go binary?

That is PocketBase.


What PocketBase Actually Is

PocketBase is an open-source backend platform that packages everything into one statically linked executable:

  • Embedded SQLite database with WAL mode and dual connection pools
  • Realtime subscriptions via Server-Sent Events (SSE)
  • Built-in authentication (email/password, OAuth2, MFA, passwordless)
  • File storage with local or S3 backends
  • Admin dashboard UI served from the same binary
  • REST-ish API for all of the above
  • Go framework - embed it in your own code for custom business logic

No separate database server. No Redis. No message queue. Just ./pocketbase serve and you're running.


The Architecture: How It Fits in One Binary

SQLite as the Foundation

PocketBase uses modernc.org/sqlite - a pure Go port of SQLite. No CGO required. This means:

  • Cross-compilation works out of the box (GOOS=linux GOARCH=amd64 go build)
  • Zero system dependencies at runtime
  • The database file is just a file - copy it, back it up, move it anywhere

Dual Database Design

PocketBase maintains two separate SQLite databases:

Database File Purpose
Main data.db Collections, records, settings, auth data
Auxiliary auxiliary.db Request logs, system metadata

Why two? Log writes never block critical record operations. Backups are simpler - back up data.db without the noise. Both run in WAL mode with optimized pragmas.

Connection Pool Architecture: Solving SQLITE_BUSY

SQLite allows one writer at a time. PocketBase solves this with separate pools per database.

The nonconcurrent pool serializes all writes through a single connection. No lock contention. No SQLITE_BUSY errors. Reads scale across many connections.

Smart Query Routing: dualDBBuilder

PocketBase automatically routes queries based on SQL type.

During transactions, both pools point to the same *dbx.TX - routing is bypassed, atomicity guaranteed.


Realtime Subscriptions: SSE, Not WebSockets

PocketBase uses Server-Sent Events (SSE) - plain HTTP, no WebSocket upgrade handshake.

Why SSE?

  • Works through every proxy, load balancer, and corporate firewall
  • Automatic reconnection built into browsers (EventSource API)
  • Simpler server implementation - just a long-lived GET /api/realtime
  • Unified API: writes go through regular REST endpoints, reads through SSE

How It Works

  1. Client connects -> GET /api/realtime -> receives PB_CONNECT with clientId
  2. Client subscribes -> POST /api/realtime with subscriptions
  3. Server broadcasts on record create/update/delete -> checks access rules -> sends SSE event

Chunked iteration (150 clients per goroutine) + errgroup = horizontal scaling without blocking the event loop.


Authentication: Batteries Included

PocketBase handles the auth flows most teams rebuild poorly:

Feature Implementation
Email/password Bcrypt, email verification, password reset
OAuth2 providers Google, GitHub, Apple, Discord, etc. - 20+ built-in
MFA (TOTP) RFC 6238, QR code generation, backup codes
Passwordless Magic links, OTP via email/SMS
Token management JWT access tokens + refresh tokens, configurable expiry
Auth collections Any collection can be an auth collection

Auth records are just records in a collection with type: "auth". The same API rules control access.


File Storage: Local or S3

Files attach to records via file field type. Storage backend is swappable.

Uploads are streaming - large files don't load into memory. Served via signed URLs or public access with token-based auth.


The Admin Dashboard: Not an Afterthought

Visit http://localhost:8090/_/ - you get:

  • Collection schema editor (drag-and-drop field types)
  • Record browser with filters, sorting, inline edit
  • User management (auth collections)
  • Settings UI (mail, S3, rate limits, CORS, logs)
  • API playground with auto-generated request snippets
  • Real-time log viewer

Built with Vue 3 + TypeScript, embedded as static assets in the binary.


Extending PocketBase: Go Framework Mode

Don't like something? Hook into it. PocketBase exposes custom routes, event hooks, and cron jobs.

Build your custom binary: go build -o myapp -> single executable with your logic baked in.


When PocketBase Shines (And When It Doesn't)

Great For

  • Side projects & MVPs - zero infra, deploy to a $5 VPS
  • Mobile app backends - realtime sync, offline-first friendly
  • Internal tools - admin UI included, auth done
  • Prototypes - schema changes via UI, instant feedback
  • Low-to-moderate write throughput - SQLite handles thousands of writes/sec on SSD

Not Ideal For

  • High-concurrency write-heavy workloads - SQLite serializes writers
  • Horizontal scaling - single-node architecture
  • Complex relational queries - no JOINs across collections
  • Multi-region active-active - not designed for geo-distribution

Quick Start: 30 Seconds to Running Backend

# Download prebuilt binary (Linux/macOS/Windows)
curl -L https://github.com/pocketbase/pocketbase/releases/download/v0.23.0/pocketbase_0.23.0_linux_amd64.zip -o pb.zip
unzip pb.zip
./pocketbase serve --http=0.0.0.0:8090
Enter fullscreen mode Exit fullscreen mode

Open http://localhost:8090/_/ -> create admin -> create collections -> done.

Or embed in Go with custom routes and hooks.


The Mental Model Shift

Most developers think "backend = separate services." PocketBase proves that for a huge class of applications, a single binary with SQLite is not a toy - it's the right architecture.

You get:

  • Zero operational burden - no services to monitor, no config drift
  • Portability - copy the binary + data dir, run anywhere
  • Speed - no network hops between app and DB
  • Simplicity - one codebase, one deploy artifact, one thing to understand

The trade-off is deliberate: you accept single-node limits in exchange for radical simplicity. For most projects, that's the correct trade-off.


Resources


Stop over-engineering your backend. Download PocketBase, run it, build your product.

Top comments (0)