July 14, 2026
My Notes on PocketBase Architecture
A personal attempt to understand what makes PocketBase simple, where it fits, and where the single-file approach starts to hurt.

I have been trying to understand PocketBase as a backend option, especially for small projects and MVPs where I do not want to spend too much time wiring together databases, auth providers, file storage, admin dashboards, and deployment plumbing.
These are my notes from studying a PocketBase architecture case study. The main thing I wanted to understand was not just “is PocketBase easy?” but also: what tradeoffs am I accepting when the backend is basically one Go binary with SQLite inside it?
The basic idea
PocketBase is an open-source backend engine that packages several common backend pieces into a single executable:
- Realtime database
- User authentication
- File storage
- Admin UI
- API rules / access control
Instead of running a separate API server, database server, auth service, and admin panel, PocketBase runs as one compiled Go application. It uses embedded SQLite for storage.
That simplicity is the appeal.
For early-stage apps, side projects, internal tools, prototypes, and MVPs, the usual distributed backend setup can feel heavier than the product itself. PocketBase tries to remove that overhead.
Why the architecture feels different
Most modern backend setups are distributed by default. A typical stack might involve:
- A frontend app
- A backend API server
- A managed database
- An auth provider
- Object storage
- A logging system
- A dashboard/admin tool
- Some deployment orchestration around all of it
PocketBase collapses much of that into one process.
The case study describes this as operating inside a single operating system process memory space, rather than coordinating multiple independent infrastructure components.
That has some very real benefits:
- Fewer moving parts
- Less configuration
- No internal network roundtrip to a database server
- Easier local development
- Easier backups, at least conceptually, because the important state lives in the PocketBase data folder
But it also means the system has very different failure modes and scaling limits.
Core pieces I noted
Embedded SQLite storage
PocketBase uses SQLite with Write-Ahead Logging, or WAL mode.
The main reason this matters is that reads can continue while a write is being committed. That helps concurrency compared to a simpler locking model.
But SQLite is still SQLite: writes are serialized at the database level. This is one of the most important constraints to remember.
For many apps, that is completely fine. For high-write workloads, it can become a bottleneck.
Examples where this might become painful:
- High-frequency analytics ingestion
- Metrics monitoring systems
- Very busy collaborative apps
- Continuous multi-user synchronization
- Anything where many users are writing at the same time
My simplified mental model is:
PocketBase can be very fast and practical for many read-heavy or moderate-write apps, but I should not pretend it behaves like a horizontally scalable distributed database.
Realtime via Server-Sent Events
PocketBase supports realtime events using Server-Sent Events, or SSE.
This is useful because realtime features are often one of the reasons people reach for Firebase or Supabase. PocketBase gives a lightweight version of that experience without needing a separate realtime service.
Built-in authentication
PocketBase includes authentication features such as:
- Email/password registration
- Token verification
- OAuth2 provider integration
- Google, GitHub, GitLab, and OIDC support, according to the notes
This is one of the most attractive parts for small apps. Auth is usually annoying to build from scratch, and having it included lowers the friction a lot.
File storage
PocketBase can manage files and map file metadata into collections.
Files can be stored locally, or configured to use an S3-compatible bucket. This matters because local file storage is simple, but it also ties you more strongly to the machine or volume where PocketBase is running.
Declarative API rules
Access control is handled through collection-level API rules.
An example from the material:
@request.auth.id != ""
This kind of rule checks request/auth state directly in the engine. I like this because it makes simple access rules fairly visible and close to the data model.
Extending PocketBase with JavaScript hooks
PocketBase can be extended through pb_hooks, using JavaScript or TypeScript-style scripting.
The notes mention hooks such as:
onRecordCreateonBootstrap
The general idea is that scripts can intercept requests, validate payloads, and run business logic before or after operations.
That sounds very convenient, but there is a big caveat.
Important caveat: this is not Node.js
PocketBase does not run hooks on Node.js, V8, or Bun.
It uses Goja, a JavaScript interpreter written in Go.
That means many npm packages will not work, especially packages that depend on Node-specific APIs like:
fscryptonet- Node-specific HTTP internals
- Native modules
Instead, PocketBase exposes its own globally injected helpers, such as:
$http.send()$os.readFile()
This is a key detail I do not want to forget. It is easy to think “JavaScript hooks” means “I can use my usual Node ecosystem.” In this case, not really.
My takeaway:
PocketBase hooks are useful for embedded backend logic, but I should treat them as PocketBase scripting, not as a full Node.js runtime.
Production constraints I would need to respect
The single-file / single-process architecture is the best part of PocketBase, but also the source of most operational limitations.
SQLite write serialization
Even with WAL mode, writes are serialized.
That does not automatically make PocketBase unsuitable for production. It just means the type of production workload matters.
I would feel more comfortable using it for:
- Small SaaS products
- Internal tools
- Admin dashboards
- MVPs
- Content apps
- Projects with moderate write traffic
I would be more cautious with:
- High-volume event ingestion
- Large social feeds
- Heavy multi-tenant write workloads
- Apps that need horizontal database scaling from the beginning
Persistent storage is required
PocketBase stores state in a local database file, commonly referred to in the notes as data.db, inside its data directory.
That means the server needs persistent disk storage.
This makes some hosting platforms a poor fit if they use ephemeral filesystems. The notes specifically mention environments such as standard Heroku dynos, base Render instances, and serverless edge runtimes as incompatible if local disk state is not preserved.
If the deployment platform destroys local storage on redeploy or restart, the database is gone unless it is backed up or attached to persistent storage.
So, a PocketBase production setup needs something like:
- A VPS with persistent disk
- A container platform with attached persistent volume
- Regular backups of the
pb_datafolder - A restore plan, not just a backup plan
Horizontal scaling is limited
This was another important reminder.
PocketBase is not meant to be scaled by running multiple stateless app instances behind a round-robin load balancer.
Because each instance would have its own local database state, multiple independent PocketBase instances do not automatically become one coherent backend.
The case study frames scaling as mostly vertical:
- More CPU
- More RAM
- Better disk
- A stronger single host
That is very different from the common cloud-native pattern of adding more stateless instances.
Single point of failure
If the host machine or its storage fails, the application layer and database are affected together.
This is part of the tradeoff. PocketBase reduces operational complexity, but the remaining machine becomes very important.
Backups, monitoring, and recovery matter more than the “one file” marketing vibe might suggest.
PocketBase and Next.js
The material also covered how PocketBase fits with Next.js, especially the Pages Router model.
Client-side usage
Using the PocketBase JS SDK directly in the browser can make sense for realtime subscriptions and low-latency reads.
The client talks directly to the PocketBase backend.
Server-side rendering adds a hop
With server-side rendering, such as getServerSideProps or internal API routes, the request path can become:
Client → Next.js Server → PocketBase Instance
That extra hop is not always a problem, but it is something to keep in mind.
Rate limiting gotcha
The notes also mention that server-side calls may come from a concentrated server IP address. That can accidentally trigger PocketBase anti-abuse rate limiters unless the configuration accounts for it.
This is the kind of small deployment detail that is easy to miss until production traffic behaves strangely.
Why PocketBase does not run directly on Vercel
A common misconception is trying to deploy PocketBase itself on Vercel.
Based on the notes, that does not fit the platform model.
Two reasons stood out:
-
Vercel compute is stateless and ephemeral
PocketBase needs persistent local storage for SQLite data. -
PocketBase is a long-running server process
Running./pocketbase serveexpects a continuous process listening on a port. Serverless functions are short-lived invocation environments, not long-running daemons.
So the recommended pattern is decoupled deployment.
A more realistic deployment shape
The frontend can live on Vercel, while PocketBase runs somewhere persistent.
For example:
- Frontend: Next.js deployed to Vercel
- Backend: PocketBase on a VPS, Fly.io, Railway, or another host with persistent volume support
The frontend points to the PocketBase backend through an environment variable.
Example from the notes, cleaned up slightly:
// lib/pocketbase.js
import PocketBase from 'pocketbase';
const pb = new PocketBase(
process.env.NEXT_PUBLIC_POCKETBASE_URL || 'http://127.0.0.1:8090'
);
export default pb;
That setup keeps Vercel doing what it is good at — frontend deployment and CDN delivery — while PocketBase runs in an environment that can actually preserve its database.
Advantages I want to remember
PocketBase seems especially appealing because of its operational simplicity.
From the case study, the main advantages are:
- Low infrastructure cost: the notes mention it can run comfortably on a low-tier VPS.
- Low database latency: SQLite is embedded, so there is no TCP roundtrip to a separate database server.
- Local and production similarity: development can look very close to production.
- Easy backup concept: copying the
pb_datafolder is central to backup strategy. - Built-in tooling: logging, migrations, scheduling, auth, storage, and admin UI are included.
This is exactly the kind of stack that feels nice when the goal is to ship something useful quickly.
Risks and limitations I want to remember
The same simplicity also creates risks:
- Single point of failure: one host carries the app and database.
- SQLite write bottlenecks: writes are serialized.
- No simple horizontal scaling: multiple stateless instances are not the default path.
- Persistent disk required: ephemeral/serverless hosting is a bad match for the backend.
- Non-standard JavaScript runtime: Goja is not Node.js.
- Project lifecycle risk: the material notes PocketBase is pre-v1.0.0, so breaking changes are a consideration.
- Maintainer risk: the case study notes it is primarily built and curated by one developer, Gani Georgiev, without enterprise-style support SLAs.
None of these automatically rule it out. They just define the boundary.
My current mental model
The cleanest way I can summarize PocketBase is:
PocketBase is a very practical backend shortcut when the product needs simplicity more than distributed scalability.
I would consider it when I want:
- A fast MVP backend
- Built-in auth
- Realtime basics
- A simple admin UI
- Low hosting cost
- Minimal infrastructure
- A backend that can run on a small VPS
I would pause before using it when I need:
- Horizontal scaling
- Very high write throughput
- Multi-region availability
- Enterprise support guarantees
- Heavy Node.js-based backend extensions
- Fully serverless backend deployment
For me, the important thing is not to treat PocketBase as “Firebase but magically simpler in every way.” It is more specific than that.
It is a compact Go + SQLite backend with a lot of useful features included. If the application fits that shape, it can remove a huge amount of backend overhead. If the application fights that shape, the simplicity can turn into a constraint.
That feels like the real lesson.