Skip to content

Environment Configuration Reference (AWS)

AWS deployment environments (dev / prd, etc.) are defined in infra/config/environments.ts (copied from environments.example.ts; forks commit it). Settings resolve in this order: CLI -c flags > env entry > scale defaults > built-in defaults. Note that -c only applies to environment entry fields (scale / dbEngine / enableOpenSearch, etc.) — for site-scoped fields (domainName / allowedIpRanges / basicAuth, etc.) the -c channel is ignored in multi-site environments (preventing one -c from stamping every site at once).

The top level of the file exports the CodeConnections connection ARN (shared by all envs):

export const connectionArn = 'arn:aws:codeconnections:...:connection/...'

The multi-site shape (declaring sites) is the standard way to create an environment. Fields split into “environment entry” fields (shared resources + CI/CD) and “site entry” fields (site-specific settings).

Separate AWS accounts are recommended for prd vs dev (isolation of failures, permissions, and billing; a contained blast radius). Setting a distinct account per environment separates them at the account boundary.

Running multiple environments in one account is also supported (for evaluation / small / cost-conscious setups), with one caveat: deploying the same commit to dev and prd near-simultaneously can race on pushing the same tag to the CDK bootstrap image ECR repository the two environments share (image tags are a hash of the build content, so the same commit yields the same tag). The conflict is transient and self-healing — re-running the failed deploy resolves it (the already-pushed image is skipped). To avoid it for good, make that ECR repository’s tags MUTABLE, or stagger the dev and prd deploys. See docs/specs/phase4-deploy.md in the repository for the procedure.

Settings for the shared resources (database, OpenSearch, VPC, ECS cluster) and CI/CD.

FieldTypeDefaultDescription
accountstringrequiredTarget AWS account ID. Misdeployment guard (CDK refuses to deploy with mismatched credentials)
regionstringap-northeast-1Target region
scalesmall | medium | largesmallDeployment size (controls resource sizing as one knob)
dbEnginerds | aurorascale-dependent (small=rds, medium/large=aurora)Database engine
enableOpenSearchbooleantruefalse → PostgreSQL full-text search fallback
bedrockobject | falseenabled (Titan v2)Semantic search and AI metadata suggestions. false disables (AI_TYPE=none)
githubRepostringnoneCodeConnections source repository (owner/repo). Envs without it get no pipeline
deployBranchstringmainBranch that deploys this env in pipeline mode
overridesdeep-partialnoneFine-grained overrides of the scale preset (see “overrides” below)
sitesSiteConfig[]none (the legacy single-site shape)The sites this environment hosts. Always declare it for new deployments (one entry is fine)

Site-specific settings. They cannot appear on the environment entry (synth fails).

FieldTypeDefaultDescription
namestringrequiredSite key (^[a-z][a-z0-9]{1,15}$), used in resource names kukan-<env>-<site>-* and database kukan_<site>
brandstringdefault (the brand brands/default)Web image brand (KUKAN_BRAND). Defaults to default; omitting it and brand: 'default' are equivalent (the brands/default brand). Any other value requires a matching apps/web/brands/<brand>/ (an unknown brand fails the image build)
domainNamestringnoneCustom domain (defaults to the CloudFront domain)
hostedZoneIdstringnoneRoute53 hosted zone ID (needed with domainName)
hostedZoneNamestringnoneRoute53 hosted zone name (same)
certificateArnstringauto-created in standalone modeus-east-1 ACM certificate ARN. Required in pipeline mode when domainName is set
webAclArnstringauto-created in standalone modeus-east-1 WAF WebACL ARN (sharable across sites). Required in pipeline mode when WAF is on
enableWafbooleanON (OFF when allowedIpRanges / basicAuth set)WAF managed rules on CloudFront (~$9/month)
allowedIpRangesstring[]noneIP restriction (CloudFront Function, IPv4 CIDR + IPv6)
basicAuth{ username, password }noneBasic auth gate, OR-combined with allowedIpRanges (light gate only)
bucketNamestringauto-namedS3 bucket name (globally unique auto-naming when omitted)
enableGa4DataApibooleanfalseGA4 access analytics dashboard
overridespartialnoneSite-owned sections only (see “overrides” below)

If you later switch certificateArn / webAclArn to external ARNs, the previously auto-created certificate / WebACL is not deleted (RemovalPolicy.RETAIN, so deleting a resource CloudFront still references cannot fail the deploy). How you clean up afterward depends on whether any managed resource remains:

  • Only one of the certificate / WAF switched to an external ARN (the other stays auto-created): the GlobalStack remains, and only the switched resource leaves the template and is detached by RETAIN. Delete it manually if unneeded
  • Both switched (i.e. the last managed resource): needsGlobalStack=false, so the whole GlobalStack drops out of the assembly — no “remove the resource” update is ever sent, and the physical GlobalStack lingers still managing the resources. Deleting the certificate / WebACL directly here would drift the stack. Instead, after confirming RETAIN is persisted with get-template, delete the GlobalStack by physical stack name (RETAIN keeps the resources alive through the stack deletion), then delete the certificate / WebACL manually if they are genuinely unused (a WebACL keeps billing while it exists)

That retain policy is only persisted to CloudFormation by a deploy where the resource is still present in the template. So upgrading from an older version that predates this behavior and switching the ARN in the same deploy would remove the resource under its old (delete) policy and fail the deploy while CloudFront still references it. On existing environments, do it in two steps (environments created fresh on a version with this behavior carry RETAIN from the first deploy, so they can switch in one):

  1. Deploy the latest version first to persist RETAIN on the GlobalStack, then confirm it landed with aws cloudformation get-template (us-east-1) — the certificate / WebACL should show DeletionPolicy: Retain
  2. Switch the ARN in a separate later deploy

Fine-grained overrides of the scale preset. They apply as a deep merge — scale defaults ← env overrides ← site overrides — and the allowed range differs per level:

  • Environment entry: every section (web / worker / db / opensearch / dbPool / backup). Shared-resource sizing, DB retention, and the AWS Backup schedule are environment-level only
  • Site entry: site-owned sections only (web / worker / dbPool, plus the S3 versioning settings of backup). Overriding db / opensearch / backup.awsBackup / backup.dbBackupRetentionDays is rejected at synth

For the per-scale default values, see “Scale defaults” in docs/specs/phase4-deploy.md in the repository.

Backward compatibility: the single-site shape

Section titled “Backward compatibility: the single-site shape”

Every site entry field except name / brand may also be written directly on the environment entry — but only in an environment that does not declare sites. This is backward compatibility with the earlier single-site shape (the all-in-one stack) and exists for already-deployed environments.

  • Do not use this shape for new deployments — declare sites even for a single site
  • Mixing the shapes (sites plus env-level site fields) is rejected at synth
  • sites cannot be added to an already-deployed single-site-shape environment (that would replace resources; see the blue/green procedure in Multi-Site Operation)