Overview
PocketBase is an open-source backend (MIT licensed) that ships as a single executable: an embedded SQLite database, an auto-generated REST API over your collections, user authentication, file uploads, realtime subscriptions, and a web admin dashboard. This template deploys one stateful workload with its data directory on a persistent volume, served over HTTPS on the canonical*.cpln.app endpoint on port 8090.
It suits a mobile or single-page app backend, a prototype that needs a real API quickly, or a small internal tool — anywhere a full PostgreSQL plus API-server plus auth-service stack would be more than the team needs.
Architecture
- PocketBase — A single-replica stateful workload running one container that serves the REST API, the realtime stream, and the
/_/dashboard on port8090. The superuser account is created from your credentials secret before the server ever binds the port, so there is no unclaimed-admin window. - SQLite on a persistent volume — The database, uploaded files, and any locally-stored backup archives all live at
/pb_dataon the workload’s volume set. There is no external database dependency; PocketBase talks to nothing but its own disk.
What Gets Created
- Stateful PocketBase Workload — One replica (
{release}-pocketbase) serving the API, realtime, and dashboard on port8090. - Volume Set — A 10 GiB persistent volume (
{release}-pocketbase-data) mounted at/pb_data, holding the SQLite database, uploaded files, and local backup archives. Scheduled snapshots protect the data, and a final snapshot is taken on uninstall. - Identity & Policy — An identity bound to the workload, with a policy granting
revealon exactly one secret: the credentials secret you create. Nothing else.
This template does not create a GVC. You must deploy it into an existing GVC.
Prerequisites
PocketBase needs one required prerequisite dictionary secret that must exist before you install. It holds the superuser login and the key that encrypts settings at rest; none of these values pass through Helm values.1
Create the credentials secret
The secret must have exactly these three keys:
openssl rand -hex 16 produces exactly the 32 characters PocketBase requires.2
Point the template at it
Set
credentials.secretName to the secret’s name (default my-pocketbase-credentials). Secrets are org-level, so no GVC flag is involved — give each release its own secret name if you run more than one.3
Keep a copy of the encryption key
Store
encryptionKey somewhere safe outside Control Plane. It cannot be changed later without orphaning everything it protects — see Important Notes.UI
Browse, install, and manage templates visually
CLI
Manage templates from your terminal
Terraform
Declare templates in your Terraform configurations
Pulumi
Declare templates in your Pulumi programs
First Steps After Install
A default install reaches ready in well under a minute. The superuser account already exists — it is created from your secret before the server starts listening — so there is nothing to claim and no open signup window.1
Sign in to the dashboard
Open
https://<canonical>.cpln.app/_/ and sign in with the email and password from your credentials secret.2
Set the Application URL
Go to Settings → Application → Application URL and set it to your public endpoint. Verification and password-reset emails build their links from this value, so until you set it those links point at the wrong host. It is a database setting, so the template cannot write it for you.
3
Configure SMTP and OAuth2 providers
Both live under Settings, in the database rather than in Helm values, and are encrypted at rest with your
encryptionKey.4
Create your collections and API rules
New collections are superuser-only until you write an API rule that opens them.
Configuration
The defaultvalues.yaml for this template:
PocketBase Instance
image— The PocketBase container image. See Image for why this is a community build and what an override must satisfy.resources— CPU and memory bounds for the container. The block exposes both a reservation and a limit, so the limit is namedmaxCpu/maxMemory; the barecpuandmemorykeys are rejected at render with a message telling you to rename them. On a stateful workload the platform caps themaxCputominCpuratio at 4:1, which the defaults sit exactly on.volumeset.capacity— Volume size in GiB (minimum 10) for/pb_data. Capacity is fixed when the volume set is created, so size it at install time.
Credentials
credentials.secretName— Name of your pre-created dictionary secret holdingemail,password, andencryptionKey(see Prerequisites). It must exist before you install, and it is the only secret the workload’s identity can reveal.
Backup
Scheduled, crash-consistent snapshots of the data volume, managed by the platform — no cloud account or bucket is required. See Backing Up for how snapshots and restores work.backup.enabled— Take periodic snapshots of the data volume (defaulttrue). Setting it tofalseremoves the schedule; the final snapshot on uninstall is taken either way.backup.schedule— Cron expression in UTC (default0 3 * * *, daily at 03:00). The platform does not accept schedules more frequent than hourly.backup.retention— How long each snapshot is kept, e.g.7d,720h,30d.
API
cors.allowedOrigins— Browser origins allowed to call the API, passed to PocketBase as its--originsflag. The default["*"]allows any origin. With a restricted list, a request from an origin that is not on it still returns200but comes back without anaccess-control-allow-originheader — which is correct CORS behavior, since the browser is what blocks the response.
A
cors.allowedOrigins change takes effect only once the new replica is serving, measured at 110 seconds after the upgrade — and the workload reports ready: true almost immediately, against the outgoing replica. Verify a CORS change with an actual request rather than by polling readiness.Access
publicAccess.enabled— Serve the REST API, realtime, and the/_/dashboard on the canonical*.cpln.appHTTPS endpoint (defaulttrue). This is safe to leave on: the superuser is created from your secret before the server starts listening, so no unclaimed admin account is ever exposed, and new collections are superuser-only until you write an API rule. Set it tofalsefor an internal-only instance — external requests are then refused at the edge with a403.internalAccess.type— Controls which workloads can reach PocketBase over the internal network:
Firewall changes are not instantaneous. Flipping
publicAccess.enabled took 126 seconds to be enforced in testing. Re-test after a pause rather than concluding the knob did not work.0.0.0.0, so the dashboard is reachable through a tunnel even with public access off and internalAccess.type: none. Forward the port and open http://localhost:8090/_/:
Image
No official PocketBase image exists. This template pins a well-used community build and overrides its entrypoint, runningpocketbase superuser upsert to completion and then exec pocketbase serve directly. The chart therefore depends only on the binary at the pinned tag, not on an entrypoint script that is versioned by the image repository rather than by PocketBase.
Connecting
Realtime Subscriptions
PocketBase delivers realtime updates over Server-Sent Events — one long-lived HTTP response, not a websocket. A client holdsGET /api/realtime open and posts its subscriptions to POST /api/realtime.
What was measured over a full ten-minute stream, kept continuously active:
- No events are lost while the stream is open — 10 of 10 record events were delivered, each carrying the mutation that triggered it.
- The cut is a clean end-of-stream, not an error or a reset. The connection simply ends.
- The cause is the platform timeout, proven causally. Lowering
timeoutSecondsto 60 cut an otherwise identical stream at exactly 60 seconds.
If someone reports that realtime “keeps dropping” or “reconnects every ten minutes”, this is the reason and it is expected behavior.
Rotating Credentials
The superuser password is re-applied from the credentials secret on every start — the container runspocketbase superuser upsert before the server binds. The secret is therefore the source of truth for the login, and changing the password in the dashboard is reverted at the next restart.
1
Update the secret
Change the
password entry of your credentials secret. Leave encryptionKey alone — see Important Notes.2
Force a redeployment
3
Wait for the new replica to serve
The rotation applies once the new replica is serving, which costs the usual restart gap of about 85 seconds (see Restarts and Availability). Until then the old password continues to work. Afterwards the old password is rejected with
400 and the new one authenticates.Restarts and Availability
PocketBase runs as exactly one replica, and there is deliberately noreplicas knob. This is upstream’s design, not a limitation of this template — PocketBase scales vertically only (“Horizontal scaling? Only on a single server”), because the database is embedded SQLite with no clustering. On this platform each stateful replica would additionally get its own volume, so a second replica would serve a different, empty database behind the same endpoint.
The practical consequence is that any restart is a full outage of about 85 seconds, during which requests fail with 503. The gap was measured three ways and landed in a tight band:
Volume detach and reattach dominates that time, which is why an unplanned replica loss costs the same as a planned restart.
Data is never at risk during a restart. The same volume reattaches to the new replica — a marker record written before a replica was stopped was readable immediately after it came back, and encrypted settings still decrypted correctly. The difference between a single instance and a highly available one here is minutes of downtime, not data loss.
Backing Up
Backups are scheduled volume snapshots managed by the platform — no cloud account or bucket is required. On the configured cron schedule the platform takes a crash-consistent snapshot of the data volume; SQLite recovers cleanly from one via its write-ahead log. Snapshots are pruned automatically afterbackup.retention, and a final snapshot is always taken when the release is uninstalled.
- Default schedule — Daily at 03:00 UTC (
backup.schedule: "0 3 * * *"), kept for 7 days (backup.retention: 7d). - Minimum interval — The platform does not accept schedules more frequent than hourly.
- Coverage — Everything under
/pb_data: the SQLite database, uploaded files, and any backup archives PocketBase itself wrote locally.
Snapshots live in the platform storage layer alongside the volume, not off-site. They protect against data corruption and accidental changes, but losing the whole GVC would lose them too. For an off-platform copy, configure PocketBase’s own S3 backups under Settings → Backups in the dashboard — that is a database setting this template deliberately does not configure, so it is yours to set up.
Restoring a Backup
Restore is in-place on the release’s own volume set: the platform provisions a fresh volume from the chosen snapshot and swaps it in, then the workload restarts to remount it.1
Find the snapshot to restore
List snapshots and note the
name, location, and volumeIndex of the one you want:2
Restore it in place
Provision a fresh volume from the snapshot and swap it in. The workload restarts to remount it:
3
Verify
Once the workload is ready again, sign in to
/_/ and confirm your collections, records, and uploaded files are present.Important Notes
- Create the credentials secret before installing.
credentials.secretNamemust name an existing dictionary secret holdingemail,password, andencryptionKey. Without it the deployment wedges silently:cpln logsreturns zero lines and the only diagnostic isstatus.versions[].messagefromcpln workload get-deployments. Recovery after creating the secret took 10 minutes 11 seconds unaided, or force a redeployment to skip the wait. - Never change
encryptionKeyafter install. It encrypts the SMTP password, OAuth2 client secrets, and S3 backup credentials stored inside the database. Changing it orphans all of them with no way back. Keep a copy outside Control Plane. - The superuser password is re-applied from the secret on every start. Changing it in the dashboard is reverted at the next restart — change it in the secret instead, and note that doing so changes your login.
- Rotating the secret needs a forced redeployment. The workload does not pick up a changed secret on its own: eleven minutes after a rotation the old password still worked and the workload reported
ready: truethroughout. See Rotating Credentials. - Realtime subscriptions are cut at ten minutes.
timeoutSecondsis already at the platform maximum of 600, so this is a hard ceiling. No events are lost and the cut is a clean end-of-stream; the official SDKs reconnect automatically, but a hand-rolled client must handle it. See Realtime Subscriptions. - Single instance, no HA — and that is upstream’s design. PocketBase does not cluster, so there is no
replicasknob and every restart is an outage of about 85 seconds. Data is not at risk; the same volume reattaches. See Restarts and Availability. - Set the Application URL at first login. Verification and password-reset emails build their links from Settings → Application → Application URL, which is a database setting the chart cannot write. Until you set it, those links point at the wrong host.
- Uploads and local backup archives share the volume with the database. A file-heavy app needs more than the 10 GiB default; raise
volumeset.capacityat install time, since capacity is fixed when the volume set is created. - Backups are platform volume snapshots, not off-site copies. They live in the platform storage layer next to the volume. For an off-platform copy, configure PocketBase’s own S3 backups in the dashboard.
- Access-knob changes take time to propagate. Flipping
publicAccess.enabledtook 126 seconds to be enforced. Re-poll rather than trusting the first response. - This is not an official image. No official PocketBase image exists, so the template pins a community build and overrides its entrypoint. The
PB_ADMIN_EMAILandPB_ADMIN_PASSWORDvariables from that image’s documentation do nothing here — PocketBase core reads no environment variables. Animageoverride must run as root withpocketbaseonPATH. - Data survives restarts and upgrades; uninstalling deletes it. The volume set goes with the release, though a final snapshot is taken on uninstall. Your credentials secret is yours and survives an uninstall.
External References
PocketBase Documentation
Official documentation for collections, rules, and the API
REST API Reference
Reading and writing records over the auto-generated API
Realtime API
Server-Sent Events subscriptions and the reconnect model
Client SDKs
Official JavaScript and Dart SDKs, which reconnect automatically
Going to Production
Upstream guidance on running PocketBase for real
PocketBase Template
View the source files, default values, and chart definition