> ## Documentation Index
> Fetch the complete documentation index at: https://synthetiq.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Multiple regions

> Run more than one region in the same AWS account, each provisioned as a cell

To run apps in more than one region, provision an additional **cell** for each region.

A cell is one `(account, region)` pair. It provisions its own regional app infrastructure and database, and acts as its own deploy target in Synthetiq.

<Note>
  This page covers multiple regions within one AWS account. The directory layout below nests each cell under its account id, so it extends to multiple accounts later. Multi-account provisioning is not yet supported.
</Note>

## Repository layout

Each cell is its own [infra root](/docs/platform-docs/deployments/byoi/ci-integration#nested-directory-layout): a directory holding `package.json`, `.npmrc`, and `_infra/synthetiq.yaml`. Organize cells by account id, then region:

```
your-repo/
├── .github/
│   └── workflows/
│       └── synthetiq-infra.yml        # one workflow, matrixed over cells
└── 111122223333/                      # your AWS account id
    ├── us-east-1/                      # the primary cell
    │   ├── package.json
    │   ├── .npmrc
    │   └── _infra/
    │       └── synthetiq.yaml          # no cell_slug
    └── ap-southeast-2/                 # an additional cell
        ├── package.json
        ├── .npmrc
        └── _infra/
            └── synthetiq.yaml          # cell_slug: ap-southeast-2
```

When adding a region to an existing single-region setup, move the current infra root into `<account-id>/<region>/` first.

## The additional cell's `synthetiq.yaml`

An additional cell is an ordinary [config](/docs/platform-docs/deployments/byoi/configuration) with two differences: it sets `cell_slug` to a unique slug (use the region), and it skips the account-shared resources the primary already owns. Your first region is the primary cell and omits `cell_slug`.

```yaml theme={null}
schema: v1
provider: aws
region: ap-southeast-2
cell_slug: ap-southeast-2
domain: apps-au.yourcompany.com
network:
  vpc: vpc-0abc123
  public_subnets: [subnet-aaa, subnet-bbb, subnet-ccc]
certs:
  api_cert_arn: arn:aws:acm:ap-southeast-2:111122223333:certificate/aaaa…
  cdn_cert_arn: arn:aws:acm:us-east-1:111122223333:certificate/bbbb…
manage:
  rds_service_linked_role: false   # primary cell owns it; once per account
  emf_extraction_policy: false     # primary cell owns it; once per account
```

Each cell needs its own setup, the same as a single region:

* **A distinct base domain.** A cell has its own edge, so two cells cannot share a domain. Give each cell its own `domain` (`apps.yourcompany.com`, `apps-au.yourcompany.com`).
* **Its own [certificates](/docs/platform-docs/deployments/byoi/certificates).** An API certificate covering `*.api.<domain>` in the cell's region, and a CDN certificate covering `*.<domain>` + apex in `us-east-1` (the edge is always in `us-east-1`, whatever the cell's region).
* **Its own [network](/docs/platform-docs/deployments/byoi/networking).** A VPC and at least three public subnets in the cell's region.
* **Its own [DNS records](/docs/platform-docs/deployments/byoi/dns).** `provision` prints the three records to create under the cell's domain.

### Account-shared resources

A few resources exist once per account. The primary cell creates them; every additional cell in the same account must skip them with the `manage` block:

| Field                            | Set on additional cells because                                                                                       |
| -------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| `manage.rds_service_linked_role` | `AWSServiceRoleForRDS` has a fixed, account-global name and exists once per account. A second cell creating it fails. |
| `manage.emf_extraction_policy`   | The metric-extraction account policy is account-level. Skip it if the primary already manages it.                     |

See [Generating synthetiq.yaml](/docs/platform-docs/deployments/byoi/configuration#fields) for the full `manage` block.

## CI for multiple cells

One workflow provisions every cell by [matrixing](/docs/platform-docs/deployments/byoi/ci-integration) the reusable job over each cell's directory. The roles and organization id are the same across cells (one account, one org); only `working-directory` varies.

```yaml theme={null}
name: synthetiq-infra
on:
  pull_request:
    paths: ["111122223333/**"]
  push:
    branches: [main]
    paths: ["111122223333/**"]
permissions:
  id-token: write
  contents: write
  pull-requests: write
jobs:
  infra:
    strategy:
      fail-fast: false        # one cell failing doesn't cancel the others
      matrix:
        working-directory:
          - 111122223333/us-east-1
          - 111122223333/ap-southeast-2
    uses: SynthetiqAI/infra-workflow/.github/workflows/plan-apply.yml@v1
    with:
      plan-role-arn: arn:aws:iam::111122223333:role/synthetiq-infra-plan
      apply-role-arn: arn:aws:iam::111122223333:role/synthetiq-infra-apply
      organization-id: <your-org-id>
      working-directory: ${{ matrix.working-directory }}
    secrets:
      SYNTHETIQ_NPM_KEY: ${{ secrets.SYNTHETIQ_NPM_KEY }}
```

Add a cell by adding its directory to the `matrix` list. Each cell plans and applies independently, so a PR touching one cell's config produces a plan for that cell only.

<Warning>
  GitHub Actions path filters are static. Point `paths:` at the account subtree (`111122223333/**`) so a change to any cell triggers the workflow. If the filter does not match, the job never runs.
</Warning>

## Walkthrough: add `ap-southeast-2`

Starting from an existing `us-east-1` cell in account `111122223333`:

<Steps>
  <Step title="Adopt the per-cell layout">
    Move the existing infra root into `111122223333/us-east-1/` if it isn't already there. The config is unchanged and the slug stays empty, so this is a no-op; `generate` reports no changes.
  </Step>

  <Step title="Create the certificates">
    Request the new cell's certificates and wait for `ISSUED`:

    * API: `*.api.apps-au.yourcompany.com` in `ap-southeast-2`
    * CDN: `*.apps-au.yourcompany.com` + apex in `us-east-1`

    See [Certificates](/docs/platform-docs/deployments/byoi/certificates).
  </Step>

  <Step title="Write the cell config">
    Create `111122223333/ap-southeast-2/` as an infra root and generate its config from inside it:

    ```bash theme={null}
    synthetiq infra init \
      --domain apps-au.yourcompany.com \
      --region ap-southeast-2 \
      --profile <aws-profile>
    ```

    Then add the multi-cell fields to the written `_infra/synthetiq.yaml`:

    ```yaml theme={null}
    cell_slug: ap-southeast-2
    manage:
      rds_service_linked_role: false
      emf_extraction_policy: false
    ```
  </Step>

  <Step title="Add the cell to CI">
    Add `111122223333/ap-southeast-2` to the workflow's `matrix.working-directory`, and confirm the trigger `paths:` still covers the account subtree.
  </Step>

  <Step title="Plan, review, apply">
    Open a PR. The plan job posts the new cell's changeset; the primary cell's job is a no-op. Merge to apply. Create the three [DNS records](/docs/platform-docs/deployments/byoi/dns) `provision` prints for the new domain.
  </Step>

  <Step title="Verify">
    List the org's deployment targets and confirm the new cell is registered:

    ```bash theme={null}
    synthetiq infra status
    ```

    You can also see it in the Synthetiq console at [console.synthetiq.com](https://console.synthetiq.com) → Integration Settings → Deployment Target. Deploy an app to it; it gets its own subdomain under the cell's domain. See [Environments](/docs/platform-docs/deployments/environments) for deploying across targets.
  </Step>
</Steps>
