Docs / Deploy contract

Deploy contract

What an app must look like to run on Launchbase, and how a release happens.

Supported stacks

static vite next node python docker

Detected from the files you upload (or the connected repository). Anything else ships with a Dockerfile.

Rules

payments
Read /docs/payments.md and get_payment_guide. manage_app_payments configures curated test/live billing. configure_app_runtime injects LB_RUNTIME_URL/TOKEN for backend /payments/{action} calls. Derive customerRef from authenticated sessions; use stable requestId, confirm paid changes, check access.get. Managed mode needs no Stripe secret key; live verification is owner-only. BYOK owns its direct Stripe integration.
port
Listen on 0.0.0.0:$PORT (3000). Never bind localhost only.
health
options.healthcheckPath defaults to /. It must return HTTP 200 without authentication; APIs should expose a dedicated endpoint.
node
package.json required. npm with package-lock.json for reproducible installs. node profile needs scripts.start; next runs next start; vite builds dist and serves SPA routes.
python
requirements.txt required. Use a Procfile web command or options.startCommand, e.g. uvicorn main:app --host 0.0.0.0 --port $PORT or gunicorn app:app --bind 0.0.0.0:$PORT. Python 3.12.
docker
Dockerfile escape hatch for other Linux stacks: install dependencies, listen on $PORT, provide CMD.
files
Relative paths, one service root. Text files as UTF-8; images, fonts, PDF and MP4/WebM video as binary. Maximum 2000 files / 20 MB decoded. Exclude .env, .git, node_modules, caches and build output. Never include provider master keys.
storage
Store end-user uploads and generated documents in Launchbase Files, never permanently in the container filesystem. Bundled assets and temporary processing may use local files. Keep file IDs and ownership in the database; authenticate every CRUD operation. Replace files by uploading a new immutable file, switching the database reference, then deleting the old file. Enable storage, configure runtime access, use /runtime/v1/files server-side. Read /docs/files-tasks.md.
cdn
Optional CDN on active paid app plans: configure_cdn or PUT /api/v1/apps/{appId}/cdn. HTML never caches; public assets can cache. Private responses require Cache-Control: private, no-store even with cookies. Read /docs/cdn.md.
recovery
restore_release redeploys old code, not data. get_recovery lists available database backups (Grow/Scale) and point-in-time ranges (Scale with the optional $129/month add-on). restore_database requires acknowledgeDataLoss:true and a stable requestId; agents can execute directly. It replaces newer database/auth changes, pauses hosting, and returns jobId to poll. Files and external payments are unchanged. Read /docs/recovery.md.
runtime
Managed database/auth wiring provides SUPABASE_URL, SUPABASE_ANON_KEY (and NEXT_PUBLIC_ variants), APP_ORIGIN and PORT. No privileged keys are ever injected.

Limits

0
One web service plus up to five background workers or scheduled tasks per app. Use deploy_task or POST /apps/{id}/tasks. Workers share Hosting capacity. Volumes and special hardware are not supported.
1
Build success plus an HTTP 200 health check is verified; business logic needs your own tests.
2
Provider log retention and ingestion delay apply; refresh logs after a failure and paginate with before.
3
Restoring a release restores source only; database changes are not reverted.

How a release happens

  1. Read GET /api/v1/discovery and this guide before building.
  2. Default: download /launchbase.mjs outside the app folder; read /docs/deploy.md. Run node launchbase.mjs deploy ./app --app APP_ID with LAUNCHBASE_TOKEN or --credential-file. Do not serialize a codebase into JSON.
  3. The helper packages local files, uploads a private tar archive and runs preflight. All upload methods share the same 2000-file / 20 MiB decoded limit.
  4. The helper persists source/release IDs and an idempotency key. Exit 2 means still deploying: repeat the same command, without --new-release. Exit 1 means inspect the detailed error and fix it.
  5. Poll the release until live or failed. On failure read build and runtime logs (paginate with before) and fix the reported error, then create a new release.
The same tools exist as JSON endpoints under https://launchbase.build/api/v1
curl -fSLo launchbase.mjs https://launchbase.build/launchbase.mjs
node launchbase.mjs deploy ./my-app --app APP_ID
# Auth: LAUNCHBASE_TOKEN or --credential-file FILE
# Exit 2: repeat the same command to follow the release
# Full instructions: https://launchbase.build/docs/deploy.md
▸ get_deploy_instructions { appId }
// Run the returned helper command in your local shell.
// Small inline examples only:
▸ validate_source   { appId, files, options: { healthcheckPath: "/health" } }
▸ upload_source     { appId, files }            // or create_upload_intent → PUT tarball → finalize_source
▸ create_release    { appId, sourceId, requestId: "v1" }
▸ get_release       { appId, releaseId }        // queued → building → starting → health_checking → live
▸ get_release_logs  { appId, releaseId, kind: "build" | "runtime" }
▸ restore_release   { appId, releaseId, requestId: "rollback-1" }
▸ connect_github      { appId, repository: "acme/notes", branch: "main", token: "github_pat_…" }
// every push to main → release github-<sha>
▸ deploy_from_github  { appId }                 // deploy the branch head now

Failure is a normal state

A failed release keeps the previous one live. Logs are real provider logs, paginated. Fix the code, create a new release with a new requestId. Nothing is deleted.