Claude Fable 5.1 & GPT-6 Astra packages are live

Environments

Free

Managing dev, staging and production — configuration injected not baked, parity that matters, environment variable validation, and safe test data.

219 lines9.5 KB Grok DevOps
targetModels
Grok 4.6Grok 4.5Grok 4 FamilyGrok Code FastFuture Grok Models
name
environments
category
DevOps
description
Managing dev, staging and production — configuration injected not baked, parity that matters, environment variable validation, and safe test data.
license
MIT
author
Agent.md maintainers
last-verified
reviewed-by
unreviewed
<!-- Generated from models/_canonical by scripts/build-model-variants.js. Edit the canonical source, not this file. Behavioural profile for Grok: scripts/model-profiles.json -->

#Non-negotiable

The constraints hoisted below override anything later in this document. Read them first; the rest is rationale.


#Non-negotiable constraints

These override anything later in this document.

  • Never build a per-environment image. docker build --build-arg ENV=prod produces something staging never tested. - Configuration arrives at runtime, from environment variables or a secret store, never from a file baked into the image. - Frontend builds are the awkward case: NEXT_PUBLIC_* and equivalent are inlined at build time. Either build per environment for those specific values and accept it, or serve them from a runtime endpoint. Decide deliberately and document it.

#Purpose

Rules for running the same software in several environments. The goal is that a change verified in one environment behaves the same in the next — which requires that the only difference between them is configuration.

If the artefact differs, the verification proved nothing. → DevOps/cicd


#One artefact, configuration injected

arduino
Build once  →  image sha256:abc…  →  staging (config A)  →  production (config B)
  • Never build a per-environment image. docker build --build-arg ENV=prod produces something staging never tested.
  • Configuration arrives at runtime, from environment variables or a secret store, never from a file baked into the image.
  • Frontend builds are the awkward case: NEXT_PUBLIC_* and equivalent are inlined at build time. Either build per environment for those specific values and accept it, or serve them from a runtime endpoint. Decide deliberately and document it.

#Validate configuration at startup

ts
const Env = z.object({
  NODE_ENV: z.enum(["development", "test", "production"]),
  DATABASE_URL: z.string().url(),
  SESSION_SECRET: z.string().min(32),
  STRIPE_KEY: z.string().startsWith("sk_"),
  LOG_LEVEL: z.enum(["debug", "info", "warn", "error"]).default("info"),
});

export const env = Env.parse(process.env);     // crash at boot, not at 3am

A missing or malformed variable should stop the process at startup, before it accepts traffic. The alternative is discovering it when one rarely-used code path runs at 3am, having reported healthy for days.

  • No defaults for secrets. A fallback SESSION_SECRET = "dev" will reach production and will be found.
  • Defaults are fine for genuinely optional tuning values.
  • Fail on unknown variables in strict deployments to catch typos (DATBASE_URL=… silently ignored is a real outage).

bash
# A production shell should be unmistakable. Same idea in the app: a banner
# rendered whenever APP_ENV != "production".
export PS1="\[\e[41;97m\] PRODUCTION \[\e[0m\] \w $ "

#The environments and what each is for

EnvironmentDataPurposeExternal services
LocalSeeded, syntheticDevelopmentStubbed or sandboxed
CIEphemeral, per runVerificationContainers, mocks
Preview (per PR)Seeded or sharedReview of one changeSandbox
StagingProduction-shaped, anonymisedPre-release verificationSandbox
ProductionRealUsersLive

Rules:

  • Every environment gets its own credentials. A key shared between staging and production means a staging compromise is a production compromise.
  • Staging uses the vendor's sandbox keys. A test run charging real cards or emailing real customers happens exactly once per organisation, and it is memorable.
  • Preview environments per pull request are worth the cost — they catch what local development cannot, and they let reviewers see the change.
  • Tear down preview environments on merge, or the cost and the credential surface grow without limit.

#Parity that matters

Full production parity is unaffordable. Match the things that change behaviour:

Must matchNeed not match
Database engine and major versionInstance size
Runtime versionReplica count
Operating system / base imageRegion count
Feature flag mechanismData volume (but see below)
Authentication flowCDN configuration

Two that are commonly wrong:

  • SQLite locally, Postgres in production guarantees behaviour differences in transactions, types, constraints and concurrency. Run the real engine locally in a container. → Database/postgres
  • Tiny staging datasets hide every query-plan problem. Query plans depend on data distribution, so a query that is instant on 100 rows can be an outage on 10 million. Use production-shaped volume where performance matters. → Database/query-optimization

#Production data does not leave production

  • Never copy a production database into staging or a laptop unmasked. It is a data breach whether or not anyone notices.
  • Restore through an anonymisation step: replace names, emails, phone numbers and payment details; keep the shape, cardinality and distribution so query plans stay representative.
  • Access to production data requires a distinct, audited, time-limited grant.
  • Deletion obligations follow the copy: a GDPR erasure request applies to the staging copy too. → Database/backup

#Make the environment obvious

Acting on production believing it is staging is a recurring and expensive class of incident.

  • Show the environment in the UI (a banner in anything non-production), in the CLI prompt, and in every log line as a field.
  • Require an explicit confirmation for destructive production commands.
  • Colour-code dashboards and terminal profiles.
  • Never point a local development environment at the production database, however briefly.
VariablePurposeSet per environment
APP_ENVThe environment's own name — drives banners and log fieldsYes
NODE_ENVFramework behaviour; only production in productionYes
DATABASE_URL / DATABASE_POOLER_URLPooled connection stringYes
DIRECT_URLUnpooled, for migrations only → Database/prismaYes
SESSION_SECRETSigning key; no default, everYes
LOG_LEVELRuntime-tunable verbosity → Backend/loggingYes
OTEL_SERVICE_NAME / OTEL_RESOURCE_ATTRIBUTESTies signals to a service and environmentYes
GIT_SHAThe deployed commit, echoed in logs and health outputYes

APP_ENV rather than overloading NODE_ENV: frameworks treat NODE_ENV as a binary production/development switch, so a staging deployment must still set NODE_ENV=production while APP_ENV=staging drives everything you control.


#Anti-patterns

Anti-patternWhy it failsFix
Per-environment buildsStaging verified something elseBuild once, promote
Configuration baked into the imageCannot promote one artefactRuntime injection
Missing variables discovered at runtimeFails on one path, at 3amValidate and crash at startup
Default value for a secretThe fallback reaches productionNo secret defaults
Typo'd variable silently ignoredFeature silently offFail on unknown variables
Shared credentials across environmentsStaging compromise reaches productionSeparate credentials
Live vendor keys in stagingReal charges, real emailsSandbox keys
Different database engine locallyBehaviour differences everywhereSame engine and major version
Tiny staging datasetQuery plans differ; outages found in productionProduction-shaped volume
Unmasked production data copied outData breachAnonymise on restore
Persistent preview environmentsUnbounded cost and credential surfaceTear down on merge
No visible environment indicatorProduction commands run by mistakeBanner, prompt, log field
Local pointed at productionOne typo destroys real dataNever

#Checklist

  • Verify: One artefact is built and promoted unchanged across environments
  • Verify: All configuration is injected at runtime
  • Verify: Build-time-inlined frontend values are an explicit, documented exception
  • Verify: Environment variables are schema-validated at startup
  • Verify: The process refuses to start on missing or malformed configuration
  • Verify: No secret has a default value
  • Verify: Unknown variables are rejected in strict deployments
  • Verify: Each environment has its own credentials
  • Verify: Staging uses sandbox keys for every external service
  • Verify: Preview environments exist per pull request and are torn down on merge
  • Verify: Database engine and major version match production everywhere
  • Verify: Runtime and base image versions match production
  • Verify: Performance-relevant environments carry production-shaped data volume
  • Verify: Production data is anonymised before entering any other environment
  • Verify: Production access is separately granted, time-limited and audited
  • Verify: The environment is visible in the UI, the shell and every log line
  • Verify: Destructive production commands require explicit confirmation