PocketBase — database, auth & files
Managed SQLite-backed backend
PocketBase is a managed SQLite-backed backend that gives you a REST API, user auth, file storage, and realtime subscriptions — all in one. It runs as a sidecar container alongside your app.
Setup
# percher.toml [data] mode = "pocketbase" # That's it. Deploy and PocketBase is ready.
Three env vars are injected automatically:
POCKETBASE_URLInternal Docker URL (server-side calls)POCKETBASE_PUBLIC_URLPublic URL with SSLVITE_POCKETBASE_URLPublic URL (Vite convention)Connecting from your app
import PocketBase from 'pocketbase'; // Server-side: use internal Docker URL (no SSL overhead) const pb = new PocketBase(process.env.POCKETBASE_URL); // Client-side (browser): use public URL with SSL const pb = new PocketBase(import.meta.env.VITE_POCKETBASE_URL); // or for Next.js: const pb = new PocketBase(process.env.NEXT_PUBLIC_POCKETBASE_URL);
CRUD operations
// Create a record
const task = await pb.collection('tasks').create({
title: 'Buy groceries',
done: false,
user: pb.authStore.record?.id,
});
// List with filters
const tasks = await pb.collection('tasks').getList(1, 20, {
filter: 'done = false',
sort: '-created',
});
// Update
await pb.collection('tasks').update(task.id, { done: true });
// Delete
await pb.collection('tasks').delete(task.id);Auth
// Sign up
await pb.collection('users').create({
email: 'user@example.com',
password: 'securepassword',
passwordConfirm: 'securepassword',
});
// Log in
const auth = await pb.collection('users').authWithPassword(
'user@example.com',
'securepassword',
);
// auth.token is now set in pb.authStore
// Check auth state
if (pb.authStore.isValid) {
console.log('Logged in as', pb.authStore.record?.email);
}File uploads
// Upload a file
const formData = new FormData();
formData.append('title', 'My photo');
formData.append('image', fileInput.files[0]);
const record = await pb.collection('posts').create(formData);
// Get file URL
const url = pb.files.getURL(record, record.image);Realtime subscriptions
// Subscribe to changes
pb.collection('messages').subscribe('*', (e) => {
console.log(e.action, e.record);
// action: 'create' | 'update' | 'delete'
});
// Unsubscribe
pb.collection('messages').unsubscribe();Admin UI
Your PocketBase admin panel is available at pb-yourapp.percher.run/_/. Use it to create collections, set API rules, and manage data. The admin password is shown once after the first deploy — save it.
Rotating the superuser password
bunx percher data reset-superuser <app> generates a new password, re-injects it asPOCKETBASE_ADMIN_PASSWORD(encrypted at rest), and updates the deployment's stored credential so percher datakeeps working. Default output confirms the rotation but doesn't print the plaintext — pass --reveal to also see the password once if you need to log into the admin UI directly. Redeploy to pick up the new credential in the running container.
Don't use PocketBase's built-in "forgot password" flow for superuser recovery — it depends on SMTP (see below), and the platform doesn't configure SMTP by default. reset-superuser is the supported recovery path.
Email (SMTP) — bring your own
Percher does not provide SMTP for your PocketBase sidecar. Sender reputation, deliverability, and cost are app-specific, so email delivery is your responsibility, not the platform's. Sidecars ship without any SMTP relay configured — every PB feature that sends mail (end-user signup verification, end-user password reset, OAuth notifications) is a silent no-op until you wire up your own provider.
Configure it in the PB admin UI: Settings → Mail settings. Pick any provider you already use — Resend, Postmark, Amazon SES, Mailgun, SendGrid, or your own SMTP server — paste the credentials, then verify with Send test email on that same page before you trust user-facing flows.
Heads-up: until SMTP is configured, PocketBase's password-reset endpoint still returns HTTP 204on the wire even though no email actually leaves the box — that's the PocketBase API contract, not a Percher quirk.