How a build runs
Every deploy builds in an isolated sandbox: its own Linux user, its own memory budget (capped per plan — see the limits), no access to other tenants or platform services. Dependency install scripts are disabled by default for supply-chain safety; if a package genuinely needs its build script (e.g. sharp), allow it explicitly with a canner.allowedBuildScripts entry in your package.json. Your node_modules and framework caches (like .next/cache) persist between builds, so rebuilds are fast.
The build log streams live in the dashboard. When the build succeeds, the new version starts, must answer the health check (respond on / — or your configured path — within 30 seconds), and only then takes over traffic. If it fails the health check, it is stopped and auto-rollback decides what happens next.
Release command
A release command runs once per production deploy: after the build succeeds, and before the new version starts. It’s the place for database migrations and seed data — npx prisma migrate deploy, drizzle-kit migrate, php artisan migrate --force, python manage.py migrate. Set it in Settings → Build.
- It runs with your app’s environment, including
DATABASE_URL. If your database gives the app a limited login, turn on Owner login for migrations in the database’s Access settings and the owner connection string is available here asDATABASE_URL_MIGRATE. It’s a session connection, so migration tools that use advisory locks work. Builds and the running app never get it. Variables scoped runtime only aren’t in the release command either. - If it fails, the deploy stops and your current version keeps running.
- It runs on its own, so a command that stops to ask a yes/no question (
Would you like to proceed? (y/N)) can’t get an answer from the build. After about 20 seconds of silence at a question, the deploy page shows it and, where answers are turned on, offers Yes and No; with nobody there it stops after 5 minutes and tells you what it was asking. To avoid the question on every deploy, give the command its non-interactive flag (--forceforprisma migrate resetandartisan migrate,--accept-data-lossforprisma db push,--noinputfor Django’scollectstatic) or pipe the answer in:printf 'y' | your-command. - It never runs on preview deploys, because previews share your production database.
Keep migrations out of the build command: a migration there runs before the build is known to be good, and on every preview deploy too.
Files that outlast a deploy
Each deploy starts from a fresh copy of your app, so a file your app writes next to its own code is replaced on the next deploy. For files that must stay, use the data directory: its path is in CANNER_DATA_DIR, it belongs to your app alone, and nothing in it changes when you deploy.
// Node
const db = new Database(path.join(process.env.CANNER_DATA_DIR ?? '.', 'app.sqlite'));
# Python
db = sqlite3.connect(os.path.join(os.environ.get("CANNER_DATA_DIR", "."), "app.db"))- It counts toward your organization’s storage, alongside databases, backups and object storage.
- It’s backed up nightly, and deleted only when you delete the project.
- Production only: preview deploys don’t get one, so a preview can’t touch production files.
- A SQLite database your app already keeps next to its code (say,
data/app.sqlite) is copied into each new deploy while the app is stopped, so it isn’t lost — unless the new deploy includes a file at that same path, which then wins. Moving it to the data directory is still the better home.
For anything shared between several processes or that needs point-in-time recovery, use a database instead.
Start command
Canner starts your app with the command it detects: your start script, or the framework’s own server. To use a different one, set a start command in Settings → Build. It replaces the detected command from your next deploy.
- It’s one line, run through
sh -cfrom your app’s directory, soNODE_ENV=production node dist/index.jsandpnpm migrate && node dist/server.jsboth work. - Listen on the port in
$PORT; Canner puts the number in for you. Any other$VARIABLEcomes from your project’s environment. - It runs exactly where your
startscript runs, as your project’s own user, so it can’t reach more than your app already can. Don’t put secrets in it: the command is shown in your deploy log. Use environment variables. - Clear the field to go back to the detected command.
Auto-rollback
When a production deploy fails to start, Canner stops it. With auto-rollback on (the default), it then rebuilds your last good commit and deploys that, so the site comes back on the previous version. Turn it off with the Auto-rollback switch on the project overview and a failed deploy stays stopped until you deploy again.
- Turn it off when a migration has already changed the database in a way the previous version can’t run against. Rebuilding the old commit would only fail again.
- It applies to deploys from GitHub. Deploys from the CLI or an upload have no earlier commit to rebuild and stay stopped either way.
- A failing release command is separate: it stops the deploy before the new version starts, so the current version keeps running.
Preview deploys
With GitHub connected, every pull request gets its own isolated preview at branch--project.canner.app, rebuilt on each push to the branch and cleaned up when the PR closes. Previews share the project’s environment variables but never its production process.
Retry, cancel, roll back
- Retry re-runs a failed build from the same commit or upload — useful after fixing an env var or when a registry hiccuped.
- Cancel stops a queued or running build.
- Rollback rebuilds any previous successful deploy from its commit and deploys it like a new one, so the commit must still be in the repository. Find it on the Deployments tab.
Sleep and wake on the free plan
Starter apps sleep after 3 hours without a request. The next visitor wakes the app automatically — they wait a few seconds while it boots, then everything is normal. Paid plans (Live and up) keep a set number of projects always on — 2 on Live, more with the always-on add-on — which is the thing to upgrade for when a real audience depends on your site.
Logs
The Logs tab streams your app’s runtime output (stdout/stderr) live. Build logs live with each deployment on the Deployments tab. If your app crashes on boot, the health-check failure message in the build log includes the tail of the runtime log — that’s the first place to look. For what specific messages mean, see common build & deploy errors.
Secrets in Canner’s request logs
Canner’s own request logs (the proxy’s access log and the platform’s request log) replace the value of these query parameters with REDACTED, so an OAuth redirect such as /callback?code=…&state=… is never written down. The URL itself, what visitors see and what your app receives are unchanged, and your app’s own log output is not touched. The match ignores case and percent-encoding; every other parameter is logged as is.
code: the OAuth authorization code a sign-in or payment provider sends back.state: the OAuth state value that ties the redirect to the session that started it.token,access_token,id_token,refresh_token: bearer, access, identity and refresh tokens.client_secret: an OAuth client secret.password: a password sent in a URL.api_key,apikey: API keys.signature,sig: webhook, request and signed-URL signatures.