Skip to content

7. Deployment

Your code is ready — now let’s get it running in AWS! Here’s how code flows from your branch to production, and how Butler gives you per-branch preview environments for free.

Diagram

Your MFE has two ways to reach an environment:

PathTriggerWhat happensEnvironment
Main pipelinePush to mainCodePipeline builds + deploys runtime stackPre-prod → Prod (with approval)
Butler sandboxPush to feature branchCodeBuild runs buildspec-ci.yaml, creates isolated stackTemporary (auto-deleted on merge)
Push to main
→ CodePipeline Source (pulls from GitHub via CodeStar)
→ Build (npm ci, test, lint, typecheck, build CDK)
→ Synth (cdk synth → CloudFormation template)
→ Self-Update (pipeline updates itself if changed)
→ Deploy (CloudFormation → ECS rolling update)

The runtime stack creates/updates: ECR image → ECS task definition → ECS service (rolling deploy, zero downtime).

Butler watches for branch pushes and runs buildspec-ci.yaml:

version: 0.2
phases:
install:
runtime-versions:
nodejs: 22
build:
commands:
- export CODEARTIFACT_AUTH_TOKEN=$(aws codeartifact get-authorization-token --domain hema-prod --domain-owner 715027721839 --region eu-central-1 --query authorizationToken --output text)
- npm config set @hema:registry https://hema-prod-715027721839.d.codeartifact.eu-central-1.amazonaws.com/npm/main/
- npm config set //hema-prod-715027721839.d.codeartifact.eu-central-1.amazonaws.com/npm/main/:_authToken $CODEARTIFACT_AUTH_TOKEN
- npm ci
- cd src && npm ci --legacy-peer-deps && cd ..
- npm run build
- export LOWERCASE_BRANCH_NAME=$(echo "$CLEAN_BRANCH_NAME" | tr '[:upper:]' '[:lower:]')
- project="your-service-$LOWERCASE_BRANCH_NAME" repo="your-service-name" branch="$BRANCH" butlerStackTag="$BUTLER_STACK_TAG" environmentName="$LOWERCASE_BRANCH_NAME" npx cdk deploy --require-approval=never

Each sandbox gets its own CloudFormation stack, ECS service, and preview URL. When the branch is merged or deleted, Butler tears down the stack automatically.

Environment variables flow into your app through two channels:

ChannelWhenWhatHow
Build-timeDocker buildNEXT_PUBLIC_* vars baked into JS bundlesBuildKit secrets or build ARGs
RuntimeContainer startServer-side secrets, feature flagsECS task definition env vars from SSM/Secrets Manager

Key variables every MFE needs:

VariablePurposeBuild/Runtime
NEXT_PUBLIC_SANITY_PROJECT_IDSanity projectBuild
NEXT_PUBLIC_SANITY_DATASETDataset (production/staging)Build
NEXT_PUBLIC_SERVICE_IDZone identifier for gatewayBuild
NEXT_PUBLIC_BASE_URLPublic URL of the serviceBuild
SANITY_API_READ_TOKENServer-side Sanity accessRuntime
AUTH_SECRETKong OAuth credentials (JSON)Runtime
ENVIRONMENTtest / preprod / prodRuntime

For the full environment landscape, see the Environment Map.