Skip to main content

Scaling to a new region

The step-by-step checklist for adding a country or region. If the earlier pages were followed, most of this is configuration, not code. Read the whole page before you start: the first section is a gate, and skipping it creates a region that claims to keep data local while it does not.

What was proven

This checklist comes from a real plan for a second region, written after a full read of the code and Terraform. The second region was not built when this was written. Steps marked as gates are things we found broken or missing at one region.

How it works​

What is new, what is shared​

The app build needs nothing new because it always asks discovery where to go. The code needs nothing new because the home region is a per-deployment setting.

How to build it​

Step 0 - the gate​

Do not create any regional resources until all of these are merged and tested.

  • Country to region map. Each region entry in the map lists the countries it serves. An unmapped country follows an explicit, logged policy. See Region discovery.
  • Clients fail closed. No client falls back to a compiled-in API address.
  • Region transfer. An operator can move a user: export, import into the target region, repoint the registry entry, verify, delete from the source. Audited.
  • Processors. Every outside service that receives user data (AI provider, email, SMS, error tracking, analytics) can run in or near the new region, and has a contract that says where it processes data. If the AI calls still go to one global endpoint, the region is local in name only.
  • Global tier scope. Someone has listed every schema in the global tier, and the privacy lead has decided whether it may be replicated. See Data residency.
  • Legal basis. For every country this region serves that is not where the region is, the legal basis for the transfer is written down by the privacy lead. That is paperwork, and it is much cheaper than a region.

Step 1 - the regional stack​

  1. Pick the AWS region. Check that every service you use exists there. Not every region has every service.
  2. Raise service quotas in that region (Fargate vCPUs first). Quotas are per account and per region. Blue/green deploys briefly need double the service's capacity.
  3. Terraform. Decide before you start: one root per region, or one root with a region variable. Do not decide halfway. Use the address slot you reserved (see Network and edge).
  4. Build the same shape as your existing prod region: VPC with three subnet tiers, NAT per AZ, the same VPC endpoints, ALB with WAF, ECS cluster, regional Aurora, Redis.
  5. ACM certificate for the region's API hostname, issued in the new region. ACM certificates are regional. CloudFront is the exception: it needs its certificate in us-east-1.
  6. User-files bucket in the new region, separate from the global content bucket.
  7. Secrets and config under a region-scoped prefix. Set the core API's sign-up home region to the new region in its task definition.
  8. Email and SMS. Verify a sending identity for email in the new region. SMS sender registrations are per country and do not carry over.
  9. Error tracking. Point the new region at an ingest endpoint in or near it, or confirm by contract where events are stored.

Step 2 - connect the global pieces​

  1. Global Postgres. Add the new region as a secondary of an Aurora Global Database: a read-only copy that AWS keeps in sync. Content writes still go to the primary region.
  2. Identity registry. Make the DynamoDB table a global table and add a replica in the new region.
  3. HMAC key. Replicate the multi-Region KMS key into the new region. Same key material means the same digest for the same email, in every region.
  4. Discovery. Run an instance in the new region. AppConfig is regional, so the new instance needs its own copy of the region map. Generate every region's copy from one source in Terraform, so they cannot drift.
  5. DNS. Point discovery.example.com at every region with Route 53 latency routing and health checks. Latency routing sends each user to the region with the fastest response. Add api.<region-code>.example.com for the new regional API.
  6. Region map. Add the entry: region code, AWS region, API endpoint, and the list of countries. This is the moment the region goes live for discovery, so do it last.

Step 3 - data transfer rules​

DataMay leave the region?
Regional Postgres rowsNo. No cross-region replicas, no cross-region snapshot copies.
Backups of the regional databaseNo. They stay in the region.
User filesNo.
LogsKeep personal data out of logs entirely. Logs stay in the region.
Analytics eventsOnly with personal fields hashed.
Global contentYes, read-only, by design.
Identity registryYes. It holds only digests and a home region.

Step 4 - prove it​

  • A synthetic request with a country code from the new region resolves to the new region, not the default.
  • A synthetic request with an unmapped country follows the written policy, and logs it.
  • A test device in the country signs up, and its rows exist only in the new region's database.
  • That user signs in from another region and is sent home.
  • AI, email and SMS calls for that user go to regional endpoints.
  • Killing discovery in one region does not stop sign-in in the other.

Cost, roughly​

As of August 2026, one prod-shaped region (ALB, Multi-AZ Aurora, Redis, ECS, endpoints, NAT) had a fixed monthly baseline before traffic. Each extra region costs about that baseline again, plus cross-region replication, plus global table writes. In our estimates, AI usage cost two to four times the infrastructure, and it grows with users, not with regions.

So: one region per country multiplies the baseline many times over. Ask the privacy lead how few regions can legally serve your markets before you plan more.

Rules​

Rule

No new region until the gate is passed and a synthetic foreign-country test proves routing, not fall-through. A region advertised as local, with users silently routed elsewhere, is worse than no region.

Rule

Add the region to the discovery map last. Until then, nothing can send users there by accident.

Rule

Every region gets the same shape as the existing prod region. A cheaper "small" second region tests a network path the first region never uses.

Mistakes we made​

  • The region map had no countries in it. Found during the plan, not after launch. See Region discovery.
  • Several building blocks were one-region only. The registry table module had no replica support. The region map was one AppConfig profile in one region. Discovery ran in one region. Each needs work before region two. Instead: check every Terraform module for multi-region support while you have one region, and fix it while nothing depends on it.
  • SMS was shaped for one country. The SMS path carried one country's sender registration fields. Instead: pick a provider and setup that works per country before launch.
  • A fresh account blocked the deploy. The default Fargate quota in a new account was below what autoscaling needed. Instead: request quotas on day one in each new account and region.

Checklist​

  • Gate passed.
  • Quotas raised in the new region.
  • Stack built with the same shape as prod.
  • Global Postgres secondary, registry replica and key replica added.
  • Discovery running in the new region, behind latency routing.
  • Region map entry added last, with its country list.
  • All proof tests pass.