Multi-Site & URL Configuration
The headless setup typically has two domains — one for the API
(TYPO3 backend) and one for the frontend app. This page is the single
source of truth for how EXT: rewrites URLs, manages cookies
and routes assets across sites.
Glossary
| Key | Meaning |
|---|---|
base | Public URL of the TYPO3 site (the API). |
frontend | Public URL of your SPA / frontend app. Used by
Url to rewrite links in the JSON
response. |
frontend | Public URL of the API as seen by browsers
going through the frontend's reverse proxy
(e.g. https://). |
frontend | Public URL for processed files (images, PDFs).
Used together with the
headless. feature flag. |
cookie | Domain to scope session cookies to. Needed when API and frontend share a root domain. |
base | Per-environment overrides of any of the above, gated by an expression-language condition. |
Single-domain setup
API and frontend both on the same host. No URL rewriting needed.
# config/sites/<identifier>/config.yaml
rootPageId: 1
base: https://example.com
headless: 1
Two-domain setup (typical)
API on api., frontend on example.. Set
frontend so URLs in the JSON response point at the frontend.
rootPageId: 1
base: https://api.example.com
headless: 1
frontendBase: https://example.com
# Optional, used with the headless.storageProxy feature flag:
# processed-file URLs are served through these proxy paths
# (page/typolink URLs always use frontendBase):
frontendApiProxy: https://example.com/headless
frontendFileApi: https://example.com/headless/fileadmin
Now any typolink or page URL in the JSON response is rewritten from
https:// to https://.
Multi-language overrides
Each language can override the URL keys independently:
languages:
- languageId: 0
title: English
base: /
locale: en_US.UTF-8
frontendBase: https://example.com
- languageId: 1
title: Deutsch
base: /de/
locale: de_DE.UTF-8
frontendBase: https://example.de
Per-environment overrides (baseVariants )
Same site, different dev/stage/prod values:
baseVariants:
- base: https://api.dev.example.com
condition: 'applicationContext == "Development"'
frontendBase: https://dev.example.com
frontendApiProxy: https://dev.example.com/headless
- base: https://api.stage.example.com
condition: 'applicationContext == "Staging"'
frontendBase: https://stage.example.com
frontendApiProxy: https://stage.example.com/headless
condition is evaluated by TYPO3CMSCore
with the site scope — available are the default variables
(application, typo3, date, features) and functions like
getenv; request is not available here.
The first variant whose condition matches wins, and its values are read verbatim: a key missing from the matching variant resolves to an empty string, it does not fall back to the site-level value — repeat every key in every variant.
XML sitemap URLs
The links in the sitemap index (the t3://
sitemap-type links) resolve through frontend; all other page
links use frontend. To make the index links use frontend
too, set:
# config/sites/<identifier>/settings.yaml
headless:
sitemap:
key: frontendBase
Index links are matched by the sitemap page type. With a custom sitemap
typeNum, set headless. (default 1533906435) as well, or
the index links keep pointing at the API host:
headless:
sitemap:
type: '2400000000'
Storage proxy (asset routing)
headless. plus frontend in the site config
makes processed-file URLs (images, PDFs) point at the frontend's
proxy instead of the TYPO3 fileadmin. Useful when you want the
browser to fetch assets from the same origin as the SPA.
$GLOBALS['TYPO3_CONF_VARS']['SYS']['features']['headless.storageProxy'] = true;