Skip to content

← Back to standards

GitHub

GitHub is our system of record for code and for how that code reaches staging, UAT, and production. We do not treat deploys as a side channel—sacred branches drive GitHub Actions to Fly.


We deploy APIs through GitHub Actions so every release is traceable: which commit, which workflow run, which person merged, and which environment received it.

That matters for engineering judgment and for compliance (SOC 2 and audits). Deploying from a laptop, or flipping “auto-deploy” on in another tool without the same history, makes it much harder to answer “what changed in production?”

GitHub is the deployment process to Fly. Fly runs the containers; GitHub decides when and from which branch they update.

What we do not do

  • Do not turn on Fly’s own auto-deploy on the app unless platform / tech lead has reviewed it with you.
  • Do not run flyctl deploy to the production org from a developer machine—that bypasses the controls we rely on.

We protect a small set of sacred branches. Each one maps to exactly one Fly config file and one workflow—the branch name is the file name. No special “production” filenames.

Sacred branchFly configDeploy workflowFly org tier
stagingfly.staging.tomlfly-deploy-staging.ymlStaging
uatfly.uat.tomlfly-deploy-uat.ymlUAT
mainfly.main.tomlfly-deploy-main.ymlProduction

main goes to the production Fly org, but the config file stays fly.main.toml—never fly.production.toml or fly.prod.toml.

Never use: fly.production.toml, fly.prod.toml, deploy-production.yml, or other one-off names that break the pattern.

Some repos only have production today (fly.main.toml only). Do not invent fake staging/UAT files until those tiers exist. Full branch rules: Branches.

Staging

Push to staging → staging workflow → staging Fly org

UAT

Push to uat → UAT workflow → UAT Fly org

Production

Push to main → main workflow → production Fly org

Each workflow runs on push to that branch only and deploys with:

flyctl deploy --config fly.<tier>.toml

Use GitHub environments and the right FLY_API_TOKEN per tier so a staging workflow cannot accidentally use a production token.

Every API repo has one shared Dockerfile. CI builds that image; Fly runs it. What changes between staging, UAT, and production is fly.staging.toml, fly.uat.toml, or fly.main.toml—not a separate Dockerfile per environment.

GitHub Actions secrets by component

Add these under Settings → Secrets and variables → Actions in the repo. Use GitHub environments (staging, uat, production) when a secret must only apply to one tier’s workflow.

Fly.io

Deploy token for the Fly org that matches the sacred branch workflow.

  • FLY_API_TOKEN — environment secret per tier

Sentry.io

Build-time source maps and release metadata in the deploy pipeline.

  • SENTRY_AUTH_TOKEN
  • SENTRY_ORG
  • SENTRY_PROJECT

Not in GitHub — runtime on Fly

These stay in fly secrets set on each tier’s app, not in Actions secrets: Fly checklist → Fly environment variables.

  • MONGODB_URI
  • CLOUDFLARE_TUNNEL_TOKEN
  • SENTRY_DSN, SENTRY_ENVIRONMENT
  • AUTH0_* — see Auth0
Merge to sacred branch → GitHub Action runs → flyctl deploy → Fly app updates
  • Fly.io — where containers run
  • Cloudflare — public hostnames and tunnel routing (set up separately from the workflow)
  • Sentry — required observability before production is “fully live”
  • Fly checklist — tier promotion checklists