PocketBase is an open-source backend that ships as a single executable file: a database, user accounts, file uploads, a live-updating API and an admin dashboard, all in one process. For a small app, one command replaces the work of wiring separate services together.
What you get in one file
Most apps need the same backend pieces: somewhere to store data, a way for people to sign up and log in, somewhere to put uploaded files, and an API the frontend can call. Usually each one is a separate service, so you run a database server, add an auth provider, set up file storage and write an API server to tie them together.
PocketBase puts all of that into one program, written in Go:
- A database: data lives in an embedded SQLite database, so there is no separate database server to install or connect to.
- Authentication: users can sign up and log in with email and password or through OAuth2 providers, and every request carries a token that says who is asking.
- File storage: a record can have file fields. Uploads are stored on the local disk by default, or in S3-compatible storage if you configure it.
- An API: every table you create gets REST-style endpoints straight away, plus realtime subscriptions so apps hear about changes as they happen.
- An admin dashboard: a web UI for creating tables, managing users and setting access rules, served by the same process.
It is one file with no external dependencies, so there is little to configure.
Running it
You download the build for your operating system from the project's releases, unzip it and start it:
./pocketbase serveThat starts a server on port 8090. The dashboard is at http://127.0.0.1:8090/_/ and the API is under http://127.0.0.1:8090/api/. The first time it runs, PocketBase opens an installer link so you can create your first superuser, the admin account that can see and change everything.
Next to the executable, it creates a pb_data folder. That folder holds the SQLite database, the uploaded files and the settings: in effect, it is your whole backend's state. Keep it out of Git, and treat it as the thing you back up.
Collections: tables with extras
In the dashboard you create collections. A collection is a table with fields (text, numbers, booleans, dates, files, relations to other collections and so on), and each row in it is a record. There are three kinds:
- Base collections hold ordinary data, such as posts, tasks or orders.
- Auth collections hold accounts. They come with email, password and token handling built in. A new project starts with a
usersauth collection. - View collections are read-only, and are defined by a SQL
SELECTquery over other collections. They suit reports and summaries.
Creating a posts collection with a title text field and an author relation to users is a few clicks, and the API for it exists the moment you save.
Talking to it from your app
Your frontend reaches PocketBase over HTTP. You can call the REST endpoints directly, for example to list the first page of posts:
curl "http://127.0.0.1:8090/api/collections/posts/records?page=1&perPage=20"Most apps use one of the official SDKs instead, which handle the token for you. With the JavaScript SDK, signing in and creating a post looks like this:
import PocketBase from "pocketbase";
const pb = new PocketBase("http://127.0.0.1:8090");
// Sign in a user from the users collection
await pb.collection("users").authWithPassword(
"kitty@example.com",
"a-strong-password"
);
// Create a record in the posts collection
const post = await pb.collection("posts").create({
title: "My first post",
author: pb.authStore.record.id,
});After authWithPassword, the SDK keeps the user's token and sends it with every request, so PocketBase knows who is creating the post.
Realtime updates
The 'realtime' part means an app can subscribe to a collection and be told when records are created, updated or deleted, without asking again and again:
pb.collection("posts").subscribe("*", (e) => {
console.log(e.action, e.record.title);
});Under the hood this uses Server-Sent Events: the app keeps one HTTP connection open and PocketBase pushes each change down it. A chat or a live dashboard needs exactly that.
API rules: who can do what
An API that exists as soon as you create a collection needs access control, and PocketBase handles it with API rules. Each collection has five, one per action: listRule, viewRule, createRule, updateRule and deleteRule.
Each rule is in one of three states:
- Locked (
null): only superusers can do it. This is the default, so a new collection is private until you open it up. - Empty: anyone can do it, including visitors who aren't signed in.
- A filter expression: only requests that match it are allowed.
The filter expressions can refer to the signed-in user through @request.auth. For the posts collection, a first set of rules might be:
createRule:@request.auth.id != "", so only signed-in users can post.updateRuleanddeleteRule:author = @request.auth.id, so people can only change their own posts.listRuleandviewRule: empty, so anyone can read them.
Rules apply to realtime subscriptions too: a subscriber only receives events for records the list or view rule would let them see. Superusers skip the rules entirely.
Here is a create request going through a rule, first without a token and then with one, and the change reaching a second app that is subscribed:
A create request checked by an API rule, then pushed in realtime
Step 1 of 6: Your app asks to create a post, but nobody has signed in yet, so there is no token.
Signing in proves who someone is; the rules decide what they may do. If those two ideas blur together, Authentication vs Authorization separates them.
Where it runs
Since PocketBase is one file with no dependencies, it runs wherever you can start a program: your laptop while you build, a cheap VPS once the app is live, or a machine in a homelab.
Deploying is mostly copying the executable to the server and starting it. If you start it with your domain name, ./pocketbase serve yourdomain.com, it gets an HTTPS certificate from Let's Encrypt by itself. You can also put it behind a reverse proxy such as Nginx or Caddy when several apps share one server. If you would rather manage self-hosted apps from a dashboard, Coolify covers that side.
For backups, the dashboard can take a ZIP snapshot of pb_data, kept locally or in S3-compatible storage. You can also copy the folder yourself, as long as PocketBase is stopped while you do.
Trade-offs and when to use it
PocketBase is aimed at small and medium apps, and its limits follow from that.
- One server: it scales vertically only, by giving the machine more CPU and memory. There is no built-in way to spread one PocketBase across several servers.
- SQLite: it is fast and simple, but it handles one write at a time. That is plenty for most side projects, internal tools and small products, and a hard ceiling for very write-heavy ones.
- Still pre-1.0: the project says full backward compatibility isn't guaranteed before v1.0, so an upgrade can need changes on your side. Read the release notes before upgrading.
- Custom logic: when the built-in API isn't enough, you can extend PocketBase with JavaScript hooks or use it as a Go framework. That works well, but it is your code to maintain.
Compared with hosted backends such as Firebase, or Supabase (which is built on Postgres), PocketBase trades managed scaling for something you can run and understand entirely yourself. It fits prototypes, hackathon projects, personal apps, internal tools and small products well. A system that needs many servers or heavy concurrent writes is better served by a client-server database.
Common mistakes
- Opening rules too wide: setting a rule to empty to 'just make it work' lets anyone, signed in or not, perform that action. Use a filter instead.
- Forgetting the owner check: a
createRulethat only checks someone is signed in still lets them setauthorto another user. Also check the submitted value, with@request.body.author = @request.auth.id. - Not backing up
pb_data: it is the whole backend. Losing the server without a backup means losing every user and every record. - Upgrading blindly: before v1.0, read the changelog first and test the upgrade on a copy of your data.
Key takeaways
- PocketBase is a whole backend in one file: SQLite database, auth, file storage, a REST-style API, realtime subscriptions and an admin dashboard.
./pocketbase servestarts it, and everything it stores lives in thepb_datafolder.- Collections are tables with an API, and API rules (locked, empty or a filter) decide who can use each action.
- Apps talk to it over REST or the SDKs, and get live changes through realtime subscriptions.
- It runs on one server, so it suits small and medium apps rather than systems that need to scale across many machines.