Skip to main content

How to Deploy

GitLab pipelines showing deploy stages and redeploy options

This guide walks you through both deployment modes in Goosehead Fastlane:

  • the promotion lane from develop through dev -> qa -> uat -> staging -> production
  • the release lane for manual release/* validation in dev, qa, or uat

Prerequisites

Before deploying, make sure you have:

  • GitLab access to the goosehead-insurance/custom-dev/goosehead-fastlane project with Maintainer or Developer role
  • dotenv-vault CLI installed: npm install -g dotenv-vault (or use npx dotenv-vault@latest)
  • Heroku team membership on the goosehead team (for viewing logs and debugging)
  • dotenv.org account with access to the goosehead-fastlane project (for managing secrets)

How Secrets Work

Fastlane uses dotenv-vault for encrypted secret management. Instead of scattering environment variables across platforms, all secrets live in a single encrypted file that's safe to commit.

The Two Pieces

PieceWhere It LivesSafe to Commit?Purpose
.env.vaultIn the Git repoYesEncrypted blobs of secrets, one per environment
DOTENV_KEYGitLab CI/CD VariablesNo, neverThe decryption key that unlocks a specific environment's secrets

Neither piece is useful alone. The .env.vault file without a DOTENV_KEY is just unreadable ciphertext. A DOTENV_KEY without the .env.vault has nothing to decrypt.

Security Model

This is a split-knowledge model. An attacker would need access to both the Git repo and the GitLab CI variables to read any secrets. Compromising one without the other reveals nothing.

Frontend vs API Gateway

The two app types decrypt secrets at different stages:

Frontend apps decrypt at build time -- the DOTENV_KEY is passed as a Docker build argument during CI, and the resulting static files have environment-specific values baked in.

The API gateway decrypts at runtime -- the Docker image ships with .env.vault inside it, and the DOTENV_KEY is set as a Heroku config var on each app. When the container starts, node -r dotenv/config main.js decrypts the vault on the fly.

Environment Promotion Chain

Code flows through five environments before reaching production:

EnvironmentHeroku PrefixTriggerApproval Requireddotenv Environment Name
Devdev-Automatic on merge to developNonedevelopment
QAtest-ManualQA lead / teamtest
UATuat-ManualQA lead / teamuat
Stagingpreprod-ManualPM / tech leadpreprod
Productionprod-ManualTech lead + PMprod

CI Prerequisites for Vault Auto-Build

The pipeline automatically rebuilds .env.vault from dotenv.org before every deploy using the build-vault job. This requires a DOTENV_ME credential in GitLab CI/CD variables.

Setting Up DOTENV_ME

  1. Get your DOTENV_ME value from the .env.me file in your local repo (the me_... token), or generate a new one by running npx dotenv-vault@latest login with an admin account
  2. Navigate to GitLab > goosehead-fastlane > Settings > CI/CD > Variables
  3. Add the variable:
KeyValueProtectedMaskedExpand
DOTENV_MEme_...YesYesNo

This only needs to be done once. The build-vault job uses this to authenticate with dotenv.org and rebuild the encrypted vault before deploy jobs run.

Setting Up DOTENV_KEY in GitLab

Each environment needs its own DOTENV_KEY configured as a GitLab CI/CD variable. You only need to do this once per environment (or when rotating keys).

Step 1: Get the Keys

Run this from the repo root to see all keys:

npx dotenv-vault@latest keys

Or get a specific environment's key:

npx dotenv-vault@latest keys development
npx dotenv-vault@latest keys test
npx dotenv-vault@latest keys uat
npx dotenv-vault@latest keys preprod
npx dotenv-vault@latest keys production

Each command outputs a URI like:

dotenv://:key_abc123...@dotenv.org/vault/.env.vault?environment=production

Step 2: Add to GitLab

  1. Navigate to GitLab > goosehead-fastlane > Settings > CI/CD
  2. Expand the Variables section
  3. Click Add variable for each environment:
KeyValueProtectedMaskedExpand
DOTENV_KEY_DEVELOPMENTdotenv://:key_...?environment=developmentYesYesNo
DOTENV_KEY_TESTdotenv://:key_...?environment=testYesYesNo
DOTENV_KEY_UATdotenv://:key_...?environment=uatYesYesNo
DOTENV_KEY_PREPRODdotenv://:key_...?environment=preprodYesYesNo
DOTENV_KEY_PRODdotenv://:key_...?environment=productionYesYesNo

When configured correctly, your CI/CD Variables page should look like this:

GitLab CI/CD Variables configured with DOTENV_KEY per environment

Protected means the variable is only available on protected branches (develop, main). Masked means the value is hidden in job logs.

Step 3: Set DOTENV_KEY on Heroku (API Gateway Only)

The API gateway decrypts at runtime, so each Heroku app needs DOTENV_KEY as a config var:

heroku config:set DOTENV_KEY='dotenv://:key_...?environment=development' -a dev-fastlane-api-gateway
heroku config:set DOTENV_KEY='dotenv://:key_...?environment=test' -a test-fastlane-api-gateway
heroku config:set DOTENV_KEY='dotenv://:key_...?environment=uat' -a uat-fastlane-api-gateway
heroku config:set DOTENV_KEY='dotenv://:key_...?environment=preprod' -a preprod-fastlane-api-gateway
heroku config:set DOTENV_KEY='dotenv://:key_...?environment=production' -a prod-fastlane-api-gateway

Deploying Step by Step

1. Merge to Develop

Every deployment starts with merging a branch into develop. This automatically triggers the pipeline.

2. Monitor the Dev Deploy

  1. Open the pipeline in GitLab > CI/CD > Pipelines
  2. deploy-dev runs automatically for the 3 core apps
  3. run-migrations-dev runs automatically if prisma/ files changed
  4. run-seed-dev is available as a manual job if you need to reseed

3. Promote Through Environments

To promote to the next environment, find the pipeline and click the Play button on the appropriate deploy job:

  1. QA: Click Play on deploy-qa -- requires QA lead approval
  2. UAT: Click Play on deploy-uat -- requires QA lead approval
  3. Staging: Click Play on deploy-staging -- requires PM / tech lead approval
  4. Production: Click Play on deploy-prod -- requires tech lead + PM approval

In the promotion lane, migrations run automatically only after deploy-dev and production deploy jobs when eligible. Seeds are always manual.

4. Verify

After each environment's deploy completes, verify the app is healthy:

  • Check the deploy job logs for Deployment successful (HTTP 200)
  • Visit the app URL (e.g., https://test-fastlane-portal.goosehead.com)
  • Check the migration job logs if database changes were involved

Running the Release Lane

Use this when you need to deploy a release/* branch to a lower environment without entering the normal develop promotion path through qa, uat, staging, and production.

1. Open Run Pipeline

Navigate to Build > Pipelines, then click Run pipeline.

2. Configure the Inputs

FieldValue
Run for branch name or tagrelease/<name>
Input: target_envdev, qa, or uat
Input: run_migrationstrue only when you want the manual migration job to appear

3. Start the Pipeline

The pipeline validates that:

  • the source is GitLab Run pipeline
  • the selected ref matches release/*
  • the target environment is one of the supported lower environments
  • the required deploy secrets are available to the pipeline

Invalid combinations fail before the image build starts.

4. Deploy the Selected Environment

Only one release deploy job appears:

InputManual Job
target_env=devdeploy-dev-release
target_env=qadeploy-qa-release
target_env=uatdeploy-uat-release

Click Play on the matching job. qa and uat still require their protected-environment approvals.

5. Run Migrations If Needed

If run_migrations=true, the matching manual migration job appears after deploy:

  • run-migrations-dev-release
  • run-migrations-qa-release
  • run-migrations-uat-release

These jobs are explicit in the release lane and do not depend on prisma diff detection.

Managing Secrets

Admin only

Managing secrets (adding, changing, removing, rebuilding the vault) requires admin/lead access on dotenv.org. Developers have pull-only access. See Updating Environment Variables for the full access control model and how to request changes.

Adding or Changing a Secret

  1. Open the dotenv.org dashboard:

    npx dotenv-vault@latest open <environment>

    Replace <environment> with development, test, uat, preprod, or production.

  2. Edit the secret in the web UI

  3. Trigger a deploy -- the build-vault CI job automatically rebuilds the vault from dotenv.org before any deploy job runs. No manual build or commit needed.

Adding a New Environment

  1. Add the environment on dotenv.org (project settings)
  2. Populate secrets via the web UI
  3. Get the key: npx dotenv-vault@latest keys <new-env>
  4. Add DOTENV_KEY_<ENV> to GitLab CI/CD Variables (Protected + Masked)
  5. For the API gateway, set DOTENV_KEY on the Heroku app via heroku config:set

Redeploying

Retry a Failed Job

If a deploy job failed (network issue, Heroku timeout, etc.), you can retry it from the pipeline UI:

  1. Open the failed pipeline
  2. Click the Retry button on the failed job
  3. The job reruns with the same context (same affected apps, same commit)

Redeploy Without New Code

To redeploy the same code (e.g., after changing a secret in the vault), you have two options:

Option A: Retry from the existing pipeline

Find the last pipeline for the commit you want to redeploy and retry the deploy job.

Option B: Trigger a new pipeline

  1. Go to CI/CD > Pipelines > Run pipeline
  2. Select branch develop for the promotion lane, or a release/* branch for the release lane
  3. For release-lane redeploys, set target_env to the lower environment you want
  4. Run the pipeline
  5. If you also need release-lane migrations, set run_migrations=true
  6. For promotion-lane migration recovery on develop, add variable FORCE_RUN_MIGRATIONS=true to bypass the prisma-change gate

Troubleshooting

"No prisma/ changes detected, skipping migrations"

The migration job detected no changes to prisma/ files. If you need to run migrations anyway, trigger a new pipeline with FORCE_RUN_MIGRATIONS=true.

Empty DOTENV_VAULT_* in .env.vault

The environment exists on dotenv.org but has no secrets populated. Open the environment in the web UI and add your secrets. The next deploy will automatically rebuild the vault with the new values.

npx dotenv-vault@latest open <environment>

build-vault Job Fails

The build-vault CI job rebuilds .env.vault from dotenv.org before every deploy. If it fails:

  1. Check that DOTENV_ME is set in GitLab > Settings > CI/CD > Variables (Protected + Masked)
  2. Verify dotenv.org is reachable (check status.dotenv.org)
  3. If dotenv.org is down, the pipeline falls back to the .env.vault committed in Git

"DOTENV_KEY is not set" in Heroku Logs

The API gateway's Heroku app is missing the DOTENV_KEY config var. Set it:

npx dotenv-vault@latest keys <environment>
heroku config:set DOTENV_KEY='<the key URI>' -a <heroku-app-name>

Deploy Job Shows "Skipping" for All Apps

All apps are deployed on every pipeline run, so this should not occur under normal circumstances. If a deploy job was skipped, retry the job or trigger a new pipeline.

Build Fails with "VITE_* undefined"

The DOTENV_KEY for that environment is either missing from GitLab CI variables or the vault doesn't contain the secret. Verify both:

  1. Check GitLab CI variables: Settings > CI/CD > Variables
  2. Check vault contents: npx dotenv-vault@latest open <environment> and confirm the VITE_* variable exists
  3. Check the build-vault job logs to ensure the vault was rebuilt successfully