Deploying from GitHub Actions
Make every push to main deploy your app. About five minutes to set up, one
command.
The idea: deploy once from your computer, then let GitHub repeat it. That
first deploy answers all the questions — which project, what to call it, how to
build it — and writes the answers into a pbc.json file. pbc ci init
then writes the workflow that repeats it, using the official
pocketbasecloud/cli/action.
Step 1 — Deploy once from your computer
In the folder you want to deploy:
pbc login
pbc frontend deploy
Use pbc pocketbase deploy for a PocketBase instance, or
pbc backend deploy for a backend. If you have no project yet, run
pbc project create my-app first.
It will ask you a few things — which project, what to name this. Answer them; this is the only time anyone has to.
If it asks about an env file, choose “Don’t push env vars.” Your .env is
almost certainly not committed to git, so GitHub would not find it and the
deploy would fail. There is a better place for secrets — see
Step 6.
When it finishes, commit the file it wrote:
git add pbc.json
git commit -m "Link this folder to PocketBase Cloud"
That file is what makes the GitHub side need no options at all.
Step 2 — Write the workflow file
pbc ci init
This writes .github/workflows/deploy.yml (or deploy-<path>.yml if this
folder is not the repo root — nested folders become deploy-apps-web.yml),
wired to the official action and to the branch you’re currently on. Pass
--branch to pin a different one. It infers everything else from pbc.json —
nothing to fill in.
It ends by printing the two steps still left, both one-time: where to copy your access token from, and the name of the repository secret to save it as. Do both now — Steps 3 and 4 below are the same two steps, spelled out.
Edit the generated file freely — running pbc ci init again will not
touch it. It prints the path and stops; pass --force when you actually want
it regenerated.
Step 3 — Copy your access token
GitHub has no browser to log in with, so it needs a token instead.
In the portal, go to Account → CLI access token → Copy.
Step 4 — Save the token in GitHub
In your repository: Settings → Secrets and variables → Actions → New repository secret.
- Name:
PBC_TOKEN - Secret: paste the token
The name has to be exactly PBC_TOKEN.
Step 5 — Push
git add .github/workflows/deploy.yml pbc.json
git commit -m "Deploy on push"
git push
Watch it run under the Actions tab. Build output (npm, and so on) is in
the job log; the CLI’s own upload and provision steps stay quiet under
--json, so they do not mix with the deploy record. The URL lands in the job
summary when it finishes. If the deploy fails, the job fails; you do not have
to check anything yourself.
That’s it. Every push to that branch now deploys.
Step 6 — If your app needs secrets
PocketBase instances and backends can hold environment variables. Set them once from your computer and GitHub will leave them alone:
pbc env set 'STRIPE_KEY=sk_live_…' --target backend --name my-api
They live on the platform, encrypted, and survive every redeploy. Quote the
whole KEY=VALUE so your shell does not split it.
Frontends are different: their variables are baked in when the site is built, so they belong in the build step, not on the platform.
- name: Build
working-directory: web
env:
VITE_API_URL: https://my-api.pocketbasecloud.com
run: |
npm ci
npm run build
- uses: pocketbasecloud/cli/[email protected]
with:
token: ${{ secrets.PBC_TOKEN }}
working-directory: web
kind: frontend
skip-build: "true"
skip-build: "true" tells the action to upload what you just built instead of
building again.
What the generated workflow actually is
pbc ci init writes something close to this — read it once, it is short:
name: Deploy
on:
push:
branches: [main]
workflow_dispatch:
concurrency:
group: deploy-production
cancel-in-progress: false
permissions:
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- uses: pocketbasecloud/cli/[email protected]
with:
token: ${{ secrets.PBC_TOKEN }}
kind: frontend
concurrency and timeout-minutes matter for reasons that are easy to
overlook and expensive to hit: without the first, two pushes in quick
succession can deploy the same resource at the same time; without the second,
GitHub’s default lets a wedged deploy run for six hours rather than
failing fast. Both are set for you.
If something goes wrong
| Message | What it means | Fix |
|---|---|---|
No token. Set 'token' to a repository secret… |
The action’s token input was empty |
Check the secret is named exactly PBC_TOKEN and that with: token: ${{ secrets.PBC_TOKEN }} is on the action step. Forked pull requests get no secrets at all — see below. |
Not authenticated. Run 'pbc login'. |
The token is expired or wrong | Copy a new one (Step 3) and update the secret. |
No project selected. Pass --project… |
No pbc.json in the checkout, or the job is running from the wrong directory |
Commit pbc.json (Step 1) and check working-directory. |
Pass --name to create the first frontend… |
The directory is not bound to a resource | Deploy once from your computer (Step 1) so pbc.json records the name, or add name: to the action. |
No pbc.json here. |
Local pbc ci init found nothing to write a workflow for |
Run Step 1 in this folder first. This sentence is from ci init, not from a failed job. |
Env file not found: .env |
pbc.json names a .env that is not in git |
Delete the "envFile" line from pbc.json, and use Step 6 instead. pbc ci init warns about this at generation time if it can. |
Build failed (npm run build exited 1) |
Your build broke, not the deploy | Run the same command locally; it will fail there too. |
Backend deployments require a Pro plan |
Plan limit | Backends need Pro. Free and Starter get 1 PocketBase and 5 frontends. |
This project has 2 computes — pass --compute |
Pro account with more than one compute | Run pbc compute ls and add compute: <id> to the action’s with: block. |
Nothing at all happened? GitHub only runs a workflow that is on the branch
you pushed to, and only for the branches listed under on:. pbc ci init
writes .github/workflows/deploy.yml at the repo root, or
.github/workflows/deploy-<path>.yml from a subdirectory (nested folders
become deploy-apps-web.yml). A subdirectory workflow also has a paths:
filter, so it only runs when the push includes that directory or the workflow
file itself. If you ran ci init on a feature branch, the file only lists that
branch — a push to main will not run it. Pass --branch main if you wanted
main.
Forked pull requests get no secrets. PBC_TOKEN arrives empty and the
action stops before touching anything. Deploy from push on your own
branches, or gate the job:
if: github.event.pull_request.head.repo.full_name == github.repository
Two things not to do
- Don’t paste the token into the workflow file. It belongs in Secrets. A workflow file is in your repository, and anyone who can read the repository can read it.
- Don’t call
pbc ... --jsonyourself and print the result. The official action already handles this for you — it masks a PocketBase deploy’s admin credentials before it reads anything else, and only ever publishes the six fields (url,id,name,status,kind,environment) as step outputs. A hand-rolledpbc pocketbase deploy --jsonstep has none of that:adminUsername/adminPasswordare fields on the record, GitHub only masks values it has been told are secret, and a generated password is not one it can guess. If you need the deploy’s URL in a later step, read it fromsteps.<id>.outputs.urlinstead.
Going further
Staging and production from the same folder, deploying several things in order, preview deploys on pull requests, exit codes, and every error message with its cause: the CI/CD reference.