Architecture
MFE Orchestrator is a control plane: it stores what your microfrontends are, which versions belong to which environment, and where their files live — then answers, at runtime, the single question your host application asks: what should I load?
This page draws that out. If you have not read Core concepts yet, start there: the boxes below are the objects described on that page.
The system at a glance
The orchestrator ships as one container, listening on port 80. Inside it there are two
processes: nginx serves the console as static files and proxies /api/ to a Node process on
localhost:3000, which is the authenticated management API and the public serve API together. All of
it therefore arrives on one port, from one image. State lives in MongoDB — Redis is optional and
holds no state, see below. Artifacts — the actual microfrontend bundles — live outside the database,
either on the orchestrator's own storage or in a cloud bucket you own.
A few things worth reading off the diagram:
- The browser never talks to your bucket. For internal storage and for
Custom Source buckets, the
serve API reads the bytes server-side with your credentials and streams them back. Your bucket
stays private and needs no CORS configuration.
Custom URL is the exception in the manifest:
the platform returns the URL and the browser fetches it itself — though
/serve/mfe/files/..., called directly for a Custom URL microfrontend, proxies those bytes server-side like any other. - The serve API is public and unauthenticated by design — it is called from browsers. The management API is the authenticated surface, used by the console and by CI with an API key.
- Artifacts are not in the database. MongoDB holds configuration and deployment snapshots; bundles live on disk or in object storage.
- Redis is optional, and caches one thing. Without
REDIS_URLthe plugin logs a warning and returns, and the platform runs without it. Its only consumer in the whole backend caches the responses of the Googletokeninfoand Auth0/userinfocalls, keyed by the token, for an hour — so local and Entra ID logins never touch it, the rate limiter keeps its counters in memory, and nothing on the serve path reads it at all. - Git providers are reached from the management API, not shown above to keep the picture readable: with a repository connected, the platform scaffolds a repo from a template, injects a build pipeline and creates the deploy secret that pipeline needs.
Deployments across environments
A project's configuration is mutable — versions, variables and storage settings are drafts. A
deployment freezes them into an immutable snapshot for one environment, and exactly one
snapshot is active per environment at any moment. That is what lets prod keep serving 1.2.0
while you stage 1.4.0 in uat from the same project.
The snapshot is a copy, not a set of references — editing a microfrontend afterwards does not reach back into it. Two consequences:
- Rollback is activation, not rebuild. Redeploying
#2inprodre-activates an older snapshot; the artifacts it points at were never deleted. - Promotion is just a deployment. Select the version live in
uat, deployprod. The bundle is not rebuilt or copied — both environments point at the same stored files, and what differs is the environment variables each snapshot carries.
Which environment a request belongs to can be given explicitly, or resolved from the browser's
Referer against the environment's allowed domains — the arrows on
the right of the diagram. That is what lets one build run unchanged in every environment.
See Deployments for the full behaviour.
How a request for a bundle is answered
The hosting type of each microfrontend decides where the bytes come from. The host application's URL does not change between the three cases — only what the orchestrator does behind it.
The entry point is always served with Cache-Control: no-cache, no-store, must-revalidate, while
the hashed assets around it stay cacheable — which is why a deployment takes effect immediately
without stale chunks. All served files carry Cross-Origin-Resource-Policy: cross-origin so a
host on a different origin can load them.
Details: Serve API reference, Hosting options, Buckets.
Artifact path layout
Both internal storage and your own bucket use the same deterministic layout, with the project id in the prefix so several projects — and several installations — can share one bucket:
<root>/<projectSlug>-<projectId>/<microfrontendSlug>/<version>/…
Versions sit side by side and nothing is overwritten on release. That is what makes rollback instant, and why you may want a lifecycle rule on old objects — see Housekeeping.
Running the orchestrator itself
The same control plane runs either as the hosted console or on your own infrastructure. Only the
API base URL differs. Self-hosted, the reference docker-compose.yaml is the container plus
MongoDB, a persistent volume and an optional Redis:
:::caution Mount the artifact folder
MICROFRONTEND_HOST_FOLDER must sit on a persistent volume. Without it, every container restart
loses the builds uploaded to the internal storage — in the reference docker-compose.yaml that is
the upload_microfrontends volume.
:::
That diagram is the Compose topology. The Helm chart is deliberately thinner: it ships the
deployment, a service, an ingress, a persistent volume claim and the environment variables, and no
database of its own — NOSQL_DATABASE_URL has to point at a MongoDB you run, and REDIS_URL
defaults to empty, which is the supported way to run without Redis at all.
MongoDB can be replaced by a managed service, and so can Redis where you run one; the identity providers, SMTP and cloud buckets are all optional. See Docker Compose, Terraform, Use external resources and the full environment variable reference.