Guides
Environments
Run production, staging and other environments of one project, each with its own URL, secrets, databases and deploys.
A project starts with one environment, production. You can add more, for example staging or qa: up to 5 per project, production included. Each environment has its own URL, secrets (ctx.env), databases, storage, Auth users, jobs, email and push settings, logs, deploys and backups. Members, roles, deploy keys, the linked repository, the slug and the custom domain belong to the project and apply to every environment. Production is the default: every deploy goes there unless it names another environment, so existing projects work exactly as before.
Create an environment
- Dashboard: the environment selector in the top bar (Organisation / Project / Environment) → New environment, or the project's Environments page (/projects/:id/environments) → New environment.
- CLI: robodev env create staging [--from production] [--branch staging]. See CLI reference (/docs/cli#env-create).
- MCP: create_environment { project_id, name, copy_from?, branch? } on robodev mcp or the hosted Robodev connector.
- REST: POST /v1/projects/:id/environments with { name, copyFrom?, branch? } returns 201 with the environment.
Names are 2–20 characters: lowercase letters, digits and single hyphens, starting with a letter and not ending with a hyphen. production and names starting with pr- are reserved. A new environment starts with its own empty databases (created by its first deploy), empty storage and no Auth users. With Copy env vars from (copyFrom / --from / copy_from) it also gets a one-time copy of that environment's secrets, Auth settings, email templates and push settings; nothing is copied without it. The copy is never live-linked: changing a value in either environment later does not change the other. Jobs and crons come from the code you deploy.
Choose the deploy target
The target is picked in this order: an explicit environment, then a branch mapping (managed GitHub workflow only), then production. An unknown name fails with 404 environment_not_found and never creates an environment.
- CLI: robodev deploy --env staging, or ROBODEV_ENV=staging (the flag wins). robodev-be deploy --env staging works the same way.
- MCP: the optional environment argument on publish_backend_file, publish_backend_files and publish_frontend_files.
- REST: POST /v1/projects/:id/deploy?environment=staging (also on the deploy-blob routes), or call the deploy route with the environment's own project id.
- The deploy answer names the environment and returns its apiUrl, appUrl and docsUrl.
Branch deploys
Each environment, production included, can map one git branch, and a branch maps to one environment only. Set it when you create the environment or later with Edit branch on the Environments page (PATCH /v1/projects/:id/environments/:env with { branch }). Production's branch defaults to the repository's default branch.
With a linked repository, the managed workflow (.github/workflows/robodev-starbase.yml) runs on a push to any branch. A short target job asks Starbase which environment the branch deploys to (GET /v1/projects/:id/environments/resolve?branch=&defaultBranch=); the deploy job runs only when it names one, and passes it as ROBODEV_ENV. A push to an unmapped branch deploys nothing. Repositories linked before environments keep the old workflow, which deploys production from the default branch; run Repair in Settings › Repository to update it. The Environments page tells you when that is needed.
Production always wins its own branch: its mapped branch, or the repository's default branch when it has none. If another environment mapped that branch before a repository was linked, pushes to it still deploy production, and the dashboard refuses new mappings to it (branch_in_use). If the target job cannot reach Starbase or gets an unexpected answer, the run fails rather than skipping the deploy.
If the repository has its own robodev:deploy script (Tiny templates), the workflow runs it for production only. Every other environment deploys with the pinned CLI, bunx robodev@0.82.0 deploy --env <name>, because an older robodev in the repository would ignore the environment and deploy to production. To use a script of your own for other environments, call robodev 0.82.0 or newer with --env from it in your own CI.
Without a linked repository, a branch is stored but nothing reads it. Deploy from your own CI instead, for example a GitHub Actions job that runs on pushes to staging:
Plain robodev deploy never reads the git branch, so CI that already deploys production keeps doing so.
URLs
- Production keeps https://{slug}.robodev.povio.dev, its Default URL https://{projectId}.robodev.povio.dev and its custom domain.
- Another environment is served at https://{slug}--{env}.robodev.povio.dev, for example acme--staging.robodev.povio.dev. When the project has no slug, the name would be longer than 63 characters, or the host is already taken, the environment is served at its own https://{environmentId}.robodev.povio.dev instead. The dashboard, robodev env url and the API always show the URL that works.
- Changing the project's slug moves every environment's URL with it.
- Custom domains are production-only.
Env vars and secrets
Secrets are per environment. Settings → Secrets shows the environment selected in the top bar. From the CLI: robodev secrets set STRIPE_KEY --env staging (also list and delete). From MCP: set_secret, list_secrets and delete_secret with environment. Values stay write-only everywhere, including the one-time copy at creation. See Secrets (/docs/secrets).
Databases and storage
Each environment has its own Postgres databases, created from robodev/database.ts by its first deploy, and its own storage. Production data is never shared with another environment, and deploying to staging only changes staging's schema. Backups run for every environment and restore into a new project, as for production.
Limits and errors
- 400 invalid_environment_name — the name breaks the rule above.
- 400 reserved_environment_name — production or a pr-* name.
- 409 environment_exists — the project already has an environment with that name.
- 409 environment_limit_reached — a project can have up to 5 environments, including production.
- 400 invalid_branch — branches are 1–255 characters, without spaces or control characters, not starting with - and not ending in .lock.
- 409 branch_in_use — another environment already deploys from that branch (production's own branch included).
- 404 environment_not_found — no environment with that name (deploy, copyFrom, PATCH, DELETE).
- 400 production_environment_required — production can't be deleted; delete the project instead.
- 400 environment_not_supported — a project-wide route (members, deploy keys, repository, slug, custom domain, security reviews, rename or delete project) was called with an environment's id. Use the project id.
- 403 user_required — creating, changing or deleting an environment needs a signed-in user, not a deploy key.
Permissions
- List environments, resolve a URL or branch, deploy to any environment, and manage its secrets, logs and worker: project Admins, project Developers, organization admins and the project's deploy key.
- Create an environment or change its branch: project Admins, project Developers and organization admins (signed in).
- Delete an environment: project Admins and organization admins (signed in).
- Run Repair in Settings › Repository (updates the managed GitHub workflow): project Admins, project Developers and organization admins (signed in), when the organization has the repository provider attached.
CLI, MCP and REST
- CLI: robodev env list [--json], robodev env create <name> [--from <env>] [--branch <branch>], robodev env url <name>, robodev env delete <name> [--yes]; --env <name> (or ROBODEV_ENV) on robodev deploy, robodev secrets list|set|delete, robodev logs and robodev restart; robodev-be deploy --env <name>.
- MCP: list_environments, create_environment, delete_environment, and an optional environment on publish_backend_file(s), publish_frontend_files, list_backend_files, read_backend_file, set_secret, list_secrets, delete_secret and restart_worker.
- REST: GET /v1/projects/:id/environments, POST /v1/projects/:id/environments, PATCH /v1/projects/:id/environments/:env, DELETE /v1/projects/:id/environments/:env, GET /v1/projects/:id/environments/resolve?branch=&defaultBranch=, POST /v1/projects/:id/deploy?environment=<name>. :env is an environment name or its id. Per-environment routes (secrets, logs, databases, storage, auth, deploy logs and so on) take the environment's own id from the list.
Agent recipe: call list_environments (or robodev env list --json) first. If staging is missing and the human asked for it, create it with create_environment { name: "staging", copy_from: "production" }. Publish with environment: "staging" and set its secrets with set_secret { environment: "staging" }. Never delete an environment unless the human asks.
Preview environments per pull request are planned.