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

# Domains

A **domain** in Frontic maps a URL (host plus optional path prefix) to a specific **scope / region / locale** combination. Every Frontic API call carries a `contextDomain` value, and Frontic matches it against the configured domain rows to decide which [scope](/project-settings/scopes), [region](/project-settings/regions), and [locale](/project-settings/locales) should resolve the response. No match → the project walks its default cascade (default scope → default region → default locale) and the request still succeeds.

Frontic supports any URL strategy you want — country TLDs (`demo-shop.de`, `demo-shop.fr`), subdomains (`de.demo-shop.com`), path prefixes (`demo-shop.com/de`), or any mix. Pick what your project demands and add a row per scope/region/locale combination.

## A typical mapping

| Domain                 | Scope    | Region              | Locale |
| ---------------------- | -------- | ------------------- | ------ |
| `demo-shop.com`        | `public` | United States (USD) | `en`   |
| `demo-shop.com/de`     | `public` | Germany (EUR)       | `de`   |
| `demo-shop.com/fr`     | `public` | France (EUR)        | `fr`   |
| `b2b.demo-shop.com`    | `b2b`    | North America (USD) | `en`   |
| `b2b.demo-shop.com/de` | `b2b`    | Germany (EUR)       | `de`   |

A single domain row binds exactly one (scope, region, locale) triple. To serve multiple locales from the same region, add one row per locale.

<Screenshot name="project-settings/domains-list" caption="Domains list — each row maps a URL pattern to a scope / region / locale" alt="Project Settings Domains page with five rows mapping demo-shop.com paths and b2b.demo-shop.com paths to scope, region, and locale combinations" />

## Configuring a domain

Open **Settings → Domains** and click **Add Domain**. Each row asks for:

* **Domain** — the host plus optional path prefix (`demo-shop.com`, `demo-shop.com/de`, `b2b.demo-shop.com`).
* **Scope** — which scope to resolve in.
* **Region** — one of the scope's regions.
* **Locale** — one of the region's supported locales.
* **Alias** — optional; an alternative URL that resolves to the same row (see below).

You can't add two rows that resolve to the same (scope, region, locale) triple — that would leave the resolver with nothing to choose between. If you need an alternative URL that resolves to the same triple, use the **Domain Alias** field instead.

Each domain (and each alias) materialises its **own full set of page URL entries** — every Page record × every routing parameter, repeated per host. The data pipeline processes those entries on every relevant change, and useless domains generate work that competes with the updates you care about. Pipeline throughput is fast, but it's not infinite; the cleanest way to keep it focused is to delete domains you've stopped using. Removing a domain row also cleans up its URL entries automatically, so the trim is safe.

## Resolution behaviour

When a request arrives with a `contextDomain`:

1. Frontic looks for the **longest matching** domain row — `demo-shop.com/de` takes precedence over `demo-shop.com` for a `contextDomain` of `demo-shop.com/de/products/…`.
2. If a row matches (either as the primary domain or via its alias), the request inherits that row's scope, region, and locale.
3. If nothing matches, Frontic walks the default chain: the project's [default scope](/project-settings/scopes#the-default-scope), then that scope's [default region](/project-settings/regions#the-default-region-per-scope), then that region's default locale. The request succeeds with the defaults rather than erroring.

`contextDomain` is one of two ways context can come in; calls can also carry a `contextKey` whose own scope/region/locale take precedence over the domain match. See [Request Context](/api-builder/overview#request-context) for the full resolution flow.

## What the domain field represents

The "domain" you configure here is the value your app passes as **`contextDomain`** on every Frontic API call. It plays two roles:

* **Context resolution** — Frontic matches the value against your configured domain rows to decide which scope, region, and locale to apply.
* **URL generation** — when a [Page](/api-builder/pages) or a [Route field](/api-builder/blocks#route) returns a URL for a record, the host portion comes from the matching domain entry. `route.url` and `route.href` carry the Frontic domain that resolved.

In most apps the value you send matches the visitor's actual request host — pass `request.host` and you're done. But it's a string your app controls, not a captive of the request URL. You can derive `contextDomain` from anywhere: a header, a routing rule, a feature flag, a user preference. That flexibility is mostly relevant when one (scope, region, locale) triple needs to serve more than one real hostname — see [Serving multiple hostnames on one triple](#serving-multiple-hostnames-on-one-triple) below.

## Domain aliases

A **Domain Alias** is an alternative URL that resolves to the same row as the primary domain. Most teams reach for it during local development — your production domain isn't what your dev server serves. Point `localhost:3000` or `my.local.test` at the production row without creating a duplicate binding:

<Screenshot name="project-settings/domain-alias" caption="Domain Alias — an alternative URL pointing at an existing domain row" alt="Domain editor showing the Domain Alias field populated with localhost:3000" />

Now requests sending `contextDomain: 'localhost:3000'` resolve to the same scope/region/locale as the production domain. One alias per domain row — for more than one alternative URL on the same triple, see [Serving multiple hostnames on one triple](#serving-multiple-hostnames-on-one-triple).

[Route fields](/api-builder/blocks#route) in the response pick up the alias too. When a request resolves via an alias, the URLs that Route fields produce — on product cards, navigation items, anything that links to a page record — come back with the alias's host instead of the primary domain. Internal linking on the alias host works without any frontend rewriting.

## Interaction with withdrawals and redirects

When a Page record is withdrawn (deleted or unpublished), Frontic can serve the old URL as a `302` redirect or a `404` depending on the Page's withdrawal strategy. See [URLs, redirects & SEO](/commerce-concepts/urls-seo) — the Page behaviour is orthogonal to domain setup but the two compose: a withdrawal happens at the Page level, domain resolution happens at the URL level.

## Serving multiple hostnames on one triple

A single domain row binds one (scope, region, locale) triple, and the resolver doesn't accept duplicates that would conflict the same triple. When you need more than one real hostname to land on the same triple — staging plus production, multiple regional vanity URLs, dynamic preview hosts — there are two patterns:

* **Add an Alias to the row** — clean when the alternatives are stable and few (production plus `localhost:3000`, or one extra vanity URL). One alias per row, set in the [Domain Alias](#domain-aliases) field. Route URLs in the response automatically use the alias's host when traffic comes through it, so internal links stay on the right host without any work in the frontend.
* **Derive `contextDomain` in the app** — clean when the set of hostnames is dynamic or numerous (preview deploys, multi-tenant routing, white-labelled subdomains). All callers pass the same `contextDomain` value to the API regardless of which real hostname served them; every caller gets the same scope/region/locale. Route responses carry the canonical Frontic domain in `url` and `href` — for internal linking on the alternative hosts, use **`route.path`** (host-relative) so links stay on whatever host the visitor came from.

Pick the alias when the list is small and predictable; pick the app-side derivation when it isn't. You can mix the two on the same project — different rows can take different approaches.

## Related

<CardGroup cols={2}>
  <Card title="Scopes" icon="layer-group" href="/project-settings/scopes">
    The top of the scope / region / locale hierarchy a domain resolves into.
  </Card>

  <Card title="Regions" icon="earth-americas" href="/project-settings/regions">
    Where currency and supported locales are defined per market.
  </Card>

  <Card title="Request Context" icon="brain" href="/api-builder/overview#request-context">
    The full resolver flow — `contextDomain`, `contextKey`, fallbacks.
  </Card>

  <Card title="URLs, redirects & SEO" icon="link" href="/commerce-concepts/urls-seo">
    How domain resolution composes with Page-level withdrawal and
    canonical URL handling.
  </Card>
</CardGroup>
