Point your CI at a PocketHost instance and every push deploys your pb_hooks, pb_migrations, pb_public, and packages. You need two things:
POCKETHOST_TOKEN.npx pockethost deploy <instance>.No password, SSH key, or saved login is needed, so it works on fresh CI runners.
Go to Account → API Tokens and click Create token:
GitHub Actions.Copy the token (ph_pat_…) right away. PocketHost stores only a hash of it, so it is shown once.
In GitHub: Settings → Secrets and variables → Actions → New repository secret. Name it POCKETHOST_TOKEN and paste the token.
main to one instance# .github/workflows/deploy.yml
name: Deploy to PocketHost
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '24'
- run: npx pockethost@latest deploy my-app
env:
POCKETHOST_TOKEN: ${{ secrets.POCKETHOST_TOKEN }} Create one instance per branch you care about (for example myapp-main and myapp-staging), give the token access to those instances, then name the target after the branch:
name: Deploy branch
on:
push:
branches: [main, staging]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '24'
- run: npx pockethost@latest deploy myapp-${{ github.ref_name }}
env:
POCKETHOST_TOKEN: ${{ secrets.POCKETHOST_TOKEN }} A push to a branch whose instance doesn’t exist (or isn’t in the token’s scope) fails with Instance '…' not found, or this token cannot access it.
If your project has a .pockethostconfig (from pockethost link), you can leave off the instance name and the linked one is used.
pb_public changed, it stops the instance for the swap and starts it again, so PocketBase never runs a half-updated set of hooks. Changes to pb_public alone go live without a restart.What gets deployed:
pb_hooks/, pb_migrations/, pb_public/, and other top-level pb_* folderspackage.json, bun.lock, bun.lockb, and patches/What never gets touched:
pb_data/ (your database and uploaded files)node_modules/ and .git* filesYour project is the source of truth. Files in pb_hooks/, pb_migrations/, pb_public/, or patches/ on the instance that aren’t in your project are removed on deploy. If you’ve edited hooks over SFTP, copy those changes into your repo before the first CI deploy.
PocketHost doesn’t install npm packages. package.json, bun.lock, and patches/ are copied like any other file, and a node_modules folder already on your instance is left alone. Most npm packages can’t run inside PocketBase’s JavaScript engine anyway, since it has no Node.js built-ins. If your hooks use a package that does work there, bundle it into a single file in pb_hooks with a bundler such as esbuild (--bundle --format=cjs --platform=neutral) and require() that file.
PocketHost used to run bun install automatically when package.json or bun.lock changed. It doesn’t anymore. If your project relies on that (for example a PocketPages app), its current node_modules keeps working. To change dependencies, bundle them into pb_hooks, or install locally and upload node_modules over SFTP.
Each deploy is recorded with its time, file count, and commit SHA. The CLI sends $GITHUB_SHA automatically. Pass --commit <sha> or -m "<note>" to set them yourself.
Any CI that can run Node 20+ works the same way: set POCKETHOST_TOKEN as a secret environment variable and run npx pockethost@latest deploy <instance>.
ph_pat_, which makes a leaked one easy to search for in logs and code.Authentication failed (POCKETHOST_TOKEN): Invalid or expired token.The token was revoked, has expired, or was pasted with a typo. Create a new one and update the secret.
This token is read-only.Create a token with Deploy + read access.
Instance '…' not found, or this token cannot access it.Check the instance name, and that the token’s instance list includes it.
… is outside the deployable setThe CLI skips files outside the folders listed above and prints a warning. To ship other files, put them under pb_public/ or pb_hooks/.