Local Development
There are two ways to build on PocketBase Cloud, and both are supported all the way to production:
- In the portal — deploy an instance first and edit collections, API rules, and hooks in its admin panel. Nothing to install; changes are live immediately.
- On your machine — run PocketBase locally with the
pbcCLI, keep your schema and hooks in Git, and deploy the directory when it’s ready. Slower to start, but you get version control, offline work, and repeatable deploys.
Using the portal
Deploy an instance (Deploying PocketBase),
then work directly in its admin panel at
https://<your-instance>.pocketbasecloud.com/_/: create collections and
fields, set API rules from the
lock icon, and add server-side logic from the instance’s Hooks tab.
This is the shortest path to a working backend. Its trade-off is that the schema
lives only on that instance — export it (Settings → Export collections, or
pbc admin collections export) if you want it in your repository.
Using the CLI
Scaffold and run
mkdir db && cd db
pbc local init
./pocketbase serve
pbc local init downloads the PocketBase binary and creates pb_hooks/,
pb_migrations/, pb_data/, and a pbc.json pinning the version.
The admin UI is at http://127.0.0.1:8090/_/ and the REST API at http://127.0.0.1:8090/api/. On the first run PocketBase prints a one-time link for creating your superuser account.
Build your schema
Use the local admin UI, or drive the local instance with the same CLI commands you’d use against a deployed one:
pbc admin use http://127.0.0.1:8090
pbc admin login
pbc admin collections create '{"name":"posts","fields":[
{"name":"title","type":"text","required":true},
{"name":"body","type":"editor"}]}'
pbc admin rules set posts --list-rule '@request.auth.id != ""'
PocketBase writes a migration file into pb_migrations/ for every schema change
you make locally, so committing that directory keeps your schema in Git.
Write hooks
Hook files are plain JavaScript in pb_hooks/, named *.pb.js. The instance
reloads them automatically when you save:
// pb_hooks/main.pb.js
routerAdd("GET", "/api/hello/{name}", (e) => {
return e.json(200, { message: `Hello ${e.request.pathValue("name")}!` });
});
See Extending with Hooks for the full API.
Deploy the same directory
pbc login
pbc pocketbase deploy --name my-app-db
The first deploy ships pb_public, pb_hooks, and pb_migrations with the new
instance — your local schema and hooks are applied on creation — and links the
directory, so later redeploys are just pbc pocketbase deploy. (If no default
project is set yet, it asks which project to use; pbc project use <name> picks
one ahead of time.)
A redeploy ships the directory again: migrations merge with the ones already on
the instance and pb_public is replaced; new migrations run on the restart.
Pin the PocketBase version
pbc local init records the version it installed in pbc.json, and deploys use
that pin, so your cloud instance runs the same build you developed against:
pbc local versions # list available releases
pbc local install 0.39.9 # switch this directory's binary and update the pin
pbc local which # show the installed binary and its pin
Override it for one deploy with pbc pocketbase deploy --pb-version 0.39.9.
Frontends and backends
The same pattern applies to the rest of your stack: one directory per resource,
each bound by its own pbc.json, all in the same project.
cd ../web && npm run dev
pbc frontend deploy --name my-app-web
cd ../api && npm run dev
pbc backend deploy --name my-app-api # Pro plan only
deploy infers how to build and package each directory and records it in that
directory’s pbc.json. Edit the block whenever the guess is wrong.
A .env beside pbc.json is pushed to the instance or backend on every deploy;
cloud-only keys are left alone. Frontend variables are baked in at build time.