First-party MFE platform: runtime composition, versioned registry delivery, and host mount contract
## Summary
Commit to **runtime composition** for GitLab's UI and build the **host-side platform** that makes it operable: how any composable UI application is published, versioned, integrity-verified, delivered, mounted, and rolled back by the `gitlab-org/gitlab` monolith.
The committed scope now is **first-party composable UI apps** — same-origin apps that ride the host session and this delivery pipeline (per Engineering leadership direction). **Standalone applications** — applications originally developed outside the monolith that bring their own authorization, such as the Artifact Registry or Aura — are the final phase of this trajectory, not the current work. Sequencing it this way deliberately defers the two hardest problems: auth (first-party remotes ride the host session; scoped credentials arrive with standalone-application integration) and hardened shared-state contracts (first-party apps agree on a simple convention). One guardrail applies throughout: **build for that future, but don't architect against it** — the mount contract stays clean, apps never reach into host internals, so the auth/isolation layer for standalone applications is additive, not a rewrite.
## Definition of done
Runtime composition is the **default way to ship composable UI at GitLab**: independent UI releases are routine on GitLab.com, self-managed parity comes from the bake pipeline, shared code is consumed through versioned packages, new apps start from the standard stack (one build preset, one curated library set — a frontend LabKit) instead of inventing their own, and the mount contract has stayed clean enough that standalone applications can integrate without rewriting a single first-party app.
The measurable path there:
### Phase 1 — Verified delivery foundation *(in review)*
The verified delivery pipeline (detailed in https://gitlab.com/gitlab-org/gitlab/-/work_items/605798: registry pin, verified bake, same-origin serving, GDK dev mode with HMR), the documented mount contract v1, and ownership of the application stack established (build preset: @slashmanov; libraries + guidelines + versioned shared packages: @ntepluhina).
**Milestone:** any first-party MFE can be pinned, baked, served same-origin, and rolled back via a pin change; a proof-of-concept app rides the pipeline end to end.
### Phase 2 — Independent release cycle
Pull-through caching of registry artifacts, admin-controlled version activation (DB override over baked), verified prefetch, atomic set-based activation, and operational monitoring. Detailed functionality, the stacked MR series, and verification: https://gitlab.com/gitlab-org/gitlab/-/work_items/605812
**Milestone:** one real first-party application ships a UI change to GitLab.com users **without a monolith deployment** — publish to registry, verified prefetch, activate; rollback is a version pin (routine) or feature flag (emergency) — while self-managed and air-gapped installs keep receiving the release-pinned, bake-verified version of the same app.
**Release-blocking distribution dependencies:** the runtime cache's configuration keys must ship in Omnibus (https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/10008) and the GitLab chart (https://gitlab.com/gitlab-org/charts/gitlab/-/issues/6578) before Phase 2 is production-capable on self-managed and Kubernetes installs: the monolith degrades gracefully without them, but a multi-node fleet requires the shared object storage location. GDK template support (https://gitlab.com/gitlab-org/gitlab-development-kit/-/issues/3336) is developer tooling, not release-blocking.
### Phase 3 — Scale across first-party surfaces
The standard application stack (see "One application stack" below): the rspack build preset (owner: @slashmanov), curated libraries + guidelines (owner: @ntepluhina), versioned `vue_shared`/`lib/utils` packages consumed by remotes, contract discipline (typed per-app props versioned with each app, capabilities validated at bake), share-scope extension to reduce per-app bundle duplication (data clients, UI foundations), and publishing governance.
**Milestone:** several surfaces from more than one team in production, all built on the standard stack; onboarding a new surface requires no platform changes.
### Phase 4 — Standalone application integration *(future, gated on Phase 3)*
The guardrail becomes the product: hardened versioned state contract, scoped credentials, and isolation for applications that originated outside the monolith and bring their own authorization — integrated through an explicit, credentialed contract instead of the implicit host session.
**Milestone:** the auth/isolation layer lands additively — existing first-party apps keep their mount contract unchanged.
## Why runtime composition
- **Standalone GitLab applications are the requirement** — products like the Artifact Registry and Aura are developed outside the monolith, on their own release cycles and with their own authorization, and still must appear as part of one coherent GitLab UI. Build-time composition cannot host an application that ships on its own cycle; only runtime composition can.
- **First-party surfaces benefit on the way** — the same mechanics give monolith surfaces independent UI releases (publish → activate, no monolith deployment).
- **The mechanics are proven** — Module Federation 2.0 runtime API on the webpack-4 host with shared singletons, demonstrated end to end in GDK with real applications: a Vue 2 remote and the Vue 3 Duo Chat remote (from gitlab-org/frontend/gitlab-mfe) riding the full registry → pin → bake → serve pipeline, including a host-shared Apollo client.
## What this epic owns
### 1. Versioned, verified delivery (in review)
Registry-backed pipeline: MFE repos publish versioned artifacts + a sidecar manifest (per-file SHA-256 digests, declared capabilities) to a package registry; the monolith pins exact versions in a committed lockfile (`config/mfe.yml`); `rake gitlab:mfe:bake` verifies **every digest before writing a single byte**; assets are served same-origin at `/-/mfe/:name/:version/*` as public immutable artifacts (no CSP changes, no CDN dependency, works for self-managed and air-gapped installs). Rollback between MFE versions is a one-line pin change.
Detailed functionality, the stacked MR series, and verification steps: https://gitlab.com/gitlab-org/gitlab/-/work_items/605798
The sidecar manifest format is documented as a standalone contract (https://gitlab.com/gitlab-org/gitlab/-/work_items/605805), with shared publishing tooling for application repos tracked in https://gitlab.com/gitlab-org/gitlab/-/work_items/605803. Wiring the bake into the monolith build pipeline (so release artifacts actually carry baked apps) is tracked in https://gitlab.com/gitlab-org/gitlab/-/work_items/605806.
### 2. Minimal runtime (mount) contract — v1
What the host passes each remote at mount, kept deliberately narrow and layered:
- **ABI**: `mount(el, props)` / `unmount(el)` — the only framework-agnostic coupling point, owned by the host.
- **Ambient services** via the Module Federation share scope: shared Vue singleton, the host's configured data clients, locale. Auth comes free via the same-origin session.
- **Typed per-app props**, assembled by the surface's host adapter: data client (validated in practice — the Duo Chat remote shares the host panel's Apollo client and cache), current user, base path, event channel. Each app versions its own props with itself.
- **Capabilities** (`requires[]` in the sidecar) instead of ambient access: apps declare the host features and flags they read, so dependencies stay auditable and flags stay removable.
### 3. One application stack — a LabKit for the frontend
What https://gitlab.com/gitlab-org/labkit and labkit-ruby are for Go and Ruby satellite services — the standard batteries for correlation, logging, metrics, error tracking, so every service does the typical things the same way — this epic builds for composable UI applications: **one blessed stack for how an app is built, wired, and observed**, so N apps don't invent N stacks.
- **Build preset** — rspack + Module Federation configuration as a consumable preset (remote entry, manifest, share-scope wiring, dev server), not per-repo hand-rolled config. **Owner: @slashmanov**, in lockstep with https://gitlab.com/groups/gitlab-org/-/work_items/22569.
- **Curated libraries + guidelines** — the standard way to do the typical things: data clients, i18n, error tracking/observability, UI foundations, testing presets, scaffolding, and the written guidelines that make the stack the default path. **Owner: @ntepluhina.**
- **Versioned shared packages** — `vue_shared` / `lib/utils` consumed by apps become versioned packages under the same ownership; the alternative (vendored point-in-time forks with no sync owner) is already producing drift. This is the stack's first concrete deliverable.
This generalizes the reusable configuration work started in `gitlab-org/frontend/gitlab-mfe` (`@gitlab-shared/*` build configs and app packages): what proved out there graduates into the platform-blessed toolkit instead of remaining private to one repo.
### 4. Rollout & operations
Pull-through caching of registry artifacts, admin-controlled version override (DB pin over baked), atomic set-based activation with verified prefetch (no partially-updated UI), per-surface feature flags with fail-loud semantics — a failed remote surfaces loudly and the flag is the rollback; there is no silent fallback masking breakage.
### 5. Pressure-testing with real apps
Every platform increment is validated against real applications, not synthetic demos: a Vue 2 remote has been delivered through the full registry → pin → bake → serve pipeline, and the Duo Chat remote (from gitlab-org/frontend/gitlab-mfe) was integrated against the real Duo panel — including the shared Apollo client — without modifying its build. Both are proofs of concept; the first production surface will be chosen with its owning team as soon as the stack above merges, so there is a contract to build against.
## Explicit boundaries (what this epic is *not*)
- **Not the Duo Chat migration.** https://gitlab.com/groups/gitlab-org/-/work_items/22314 owns the Duo Chat pilot surface and its application code. The *reusable* configuration work started in `gitlab-org/frontend/gitlab-mfe` (`@gitlab-shared/*` build configs and app packages) graduates into the standard application stack owned by this epic; the surface itself remains a consumer of the platform. This epic owns no product surface.
- **Not the build-tool migration.** https://gitlab.com/groups/gitlab-org/-/work_items/22569 owns Rspack adoption. This epic only sets the interop requirement it validated empirically — remotes must be standard share-scope consumers (rspack/webpack `ModuleFederationPlugin`; `@module-federation/vite` remotes resolve shared modules through a private cache and are not interop-safe with the host scope) — and consumes that epic's outcome as the application stack's build preset (owner: @slashmanov on both sides, so they cannot diverge).
- **Not standalone-application integration yet.** Scoped credentials, isolation, and hardened state contracts belong to Phase 4 and start only once the first-party platform is proven at scale. Until then the mount contract is merely kept clean enough that this layer arrives as an addition, not a rewrite.
epic