Guides

Variables

Project, service, and env-group keys; per-environment overlays; matrix; references; and Share to project — not deployment stages.

Scopes

ScopeWhereUse for
ProjectProject → VariablesShared defaults inherited by every service in the active environment
Env groupProject → Env groupsNamed bundles (e.g. backend) attached to selected services
ServiceService → VariablesOverrides and service-only secrets for that service instance

Sensitive values are encrypted at rest. Prefer service or group scope for credentials that must not leak across unrelated services.

Naming: A Bytstack workspace is billing/team membership — not an env scope. Do not say “workspace env” when you mean Variables. Named stages (testing / staging / production) are deployment environments — Values overlay per environment.

Per-environment overlays

When deployment environments are enabled, the same key names exist across stages, but values are stored per environment (?environment= on project/group APIs). The header switcher (or CLI bytstack environment select) picks which overlay you edit.

Matrix

Project → Variables shows a matrix: rows = keys in the selected scope (project or a group), columns = persistent environments. Cells show masked secrets, value previews, or empty (needs a value). Click a cell to edit that environment only.

After Duplicate, a banner lists blank secrets on the new stage — fill them before expecting the app to boot.

Merge precedence

At deploy / runtime merge (lowest → highest wins):

  1. Platform inject (PORT, DATABASE_URL, BYTSTACK_*, …)
  2. Project variables (for the current environment)
  3. Attached env groups (oldest attachment first when keys collide across groups)
  4. Service variables
  5. Resolved references ${{…}} (fail closed if unresolved)

Changing project, group, or service env that requires a new process typically queues an env_change redeploy for affected services only.

Draft editor (batch apply)

With env_draft_editor enabled, Project / Service / Group Variables pages use a draft:

  1. Edit rows in place (click to edit; secrets support Reveal or write-only set).
  2. Paste .env → preview add/update/unchanged → Add to draft.
  3. Save N changes once → one redeploy confirm → one deploy per affected service.

If a deploy is already running, env is still saved and redeploy is queued until that deployment finishes (you will not see a false “redeployed” toast).

CLI equivalent: bytstack env push --dry-run then bytstack env push --overwrite.

Env groups

Attachable groups (flag: env_groups) let api + worker share STRIPE_SECRET without putting it on web.

Typical flow:

  1. Create group backend on the project.
  2. Set keys on the group for the active environment.
  3. Attach to api and worker.
  4. Edit a group var → only attached services redeploy.

Dashboard: Project → Env groups. CLI: bytstack env groups … (CLI).

Plan caps

PlanMax groups per project
Free1
Starter5
Pro25

See Pricing & limits.

References

When env_references is enabled, values may reference other scopes in the same project and same deployment environment:

SyntaxResolves to
${{project.KEY}}Project env (this environment)
${{group.name.KEY}}Env group variable (this environment)
${{service.name.URL}}Service public URL in this environment (and similar bindables)
${{database.name.URL}}Managed database URL in this environment
${{self.URL}}Current service URL

Rules:

  • Project-scoped only — no cross-project refs.
  • In-environment — ${{service.api.URL}} never resolves to another stage’s host.
  • Cycles and missing targets fail the deploy (env_reference_unresolved / env_reference_cycle).
  • Prefer public prefixes (NEXT_PUBLIC_*, VITE_*) when the browser must see a URL.

Share to project

Share to project copies a service key up to the project overlay (optional delete of the service copy). Use when a value started as service-local and should become the stack default for that environment. Redeploys all services in the project for that environment.

POST /v1/services/:id/env/:key/promote

This is not environment Promote (image digest between stages). CLI: bytstack env promote vs bytstack environment promote.

Build-time vs runtime

Service typeWhen vars are applied
StaticBuild time — baked into the asset bundle. Changing env triggers a rebuild.
Web / worker / cronRuntime injection (and during image build when a build step runs)

Services with bake env at build may rebuild on Promote so the target environment’s values are applied.

Public / client prefixes

Values that must ship to the browser are available at build time for frameworks that inline them. Treat public prefixes as non-secret.

Platform-injected vars

Do not set these yourself unless you know why:

VariableMeaning
PORTHTTP listen port for web services
NODE_ENVTypically production
DATABASE_URLInternal DB URL when a managed database is attached
BYTSTACK_SERVICE_IDCurrent service id
BYTSTACK_DEPLOYMENT_IDCurrent deployment id
BYTSTACK_APEX_HOSTApex host for path-based SaaS routing
BYTSTACK_API_PATHAPI path prefix when using path split
BYTSTACK_EDGE_TARGETEdge routing target metadata

See Platform reference.

Compose secrets

Monorepo import may detect Postgres in docker-compose.yml and offer managed Postgres. Compose passwords, Redis URLs, and other compose secrets are never written to the env store or audit payloads. Use platform DATABASE_URL after accepting the offer — see Monorepos.

CLI

bytstack environment select staging   # which overlay for project-scoped env
bytstack env list --scope project
bytstack env set KEY=value
bytstack env pull --scope project --file .env.staging
bytstack env push --scope project --overwrite --yes
bytstack env groups list
bytstack env groups create backend
bytstack env groups set backend STRIPE_KEY=sk_…
bytstack env groups attach backend api

Naming tips

  • Use conventional names (DATABASE_URL, REDIS_URL) so frameworks pick them up.
  • Managed Redis injects the first instance as REDIS_URL (per environment). Extra instances use REDIS_URL_<LOGICAL_KEY> unless you set a custom envKey. Prefer ${{redis.<logicalKey>.REDIS_URL}} when a service should pin a specific instance. Guide: Redis.
  • PR preview environments do not get a dedicated Redis. If preview services still reference staging Redis / REDIS_URL, treat keys as non-secret or omit Redis for previews.
  • Never commit secrets to git — store them in Bytstack Variables.
  • For cross-service URLs prefer ${{service.api.URL}} over hard-coded hosts (same environment only).