Skip to content

Manifest Contract

The manifest is the single source of truth for how the host treats your feature.

Authoring vs generated fields

This is the most important distinction:

  • Source manifest (examples/feature-*/manifest.json) is what teams edit.
  • Published manifest (artifacts/feature-*/<version>/manifest.json) is what the host loads.

With the default publish scripts, you usually do not need to maintain every runtime field manually.

FieldSource manifest (examples/*)Published manifest (artifacts/*)Notes
idRequired (manual)RequiredTeam-owned identifier
versionRequired (manual)RequiredMust match release version
displayNameRequired (manual)RequiredUI label
featureTypeOptional (manual)Required (normalized)domain (default) or facet (application/module aliases accepted)
mount.pathPrefixRequired for domain; optional for facetSameMount/routing base
mount.domElementIdRequired for domain; optional for facetSameRoot DOM mount id
channelOptional (manual)Required (normalized)Defaults to stable
requirements.*Optional (manual)OptionalauthRequired and minHostVersion
runtime.permissions.*Optional (manual)OptionalHost capability scoping
visibilityOptional (manual)OptionalMetadata only; host does not enforce
serverFunctions.module/endpointOptional (manual)OptionalNeeded only if feature exposes RPC
routesSeed/manualRequired for domain; optional for facetDefault publish scripts derive from router source
module.mountExport/module.unmountExportOptional/manualOptionalModule loader export names (defaults: mount/unmount)
serverFunctions.exportsSeed/manualRequired when serverFunctions presentDefault publish scripts derive from src/actions.server.js
sharedOptional/manualOptionalDefault publish scripts derive from package deps (React packages)
entrypoints.js/cssAutoRequired (js) / optional (css)Built asset paths
integrityAutoRequired in runtimeSRI hashes for entrypoint assets
signatureAutoRequired in runtimeEd25519 manifest signature
metadataAutoOptionalBuild timestamp/git SHA

Do teams need to list every route manually?

Not with the default setup. The example publish scripts parse route definitions from src/App.jsx and write manifest.routes during publish.

You should still keep the source manifest meaningful because:

  • Route extraction is static analysis, so unusual routing patterns may require manual/custom publish logic.
  • If you build your own publish pipeline, you must still output valid runtime routes.

Complete example

Application feature (route-owned)

json
{
  "id": "feature-my-feature",
  "version": "1.0.0",
  "displayName": "My Feature",
  "channel": "stable",
  "mount": {
    "pathPrefix": "/my-feature",
    "domElementId": "feature-root"
  },
  "routes": ["/my-feature", "/my-feature/*"],
  "requirements": {
    "authRequired": true,
    "minHostVersion": "1.0.0"
  },
  "visibility": {
    "ownerTeam": "team-my-feature",
    "notes": "Optional feature-owned metadata"
  },
  "shared": {
    "react": { "singleton": true, "requiredVersion": "^19.0.0" },
    "react-dom": { "singleton": true, "requiredVersion": "^19.0.0" },
    "react-router-dom": { "singleton": true, "requiredVersion": "^7.1.0" }
  },
  "runtime": {
    "permissions": {
      "eventBus": {
        "publish": ["my-feature:*"],
        "subscribe": ["*:*"]
      },
      "hostStore": {
        "read": ["*"],
        "write": ["locale", "theme"],
        "subscribe": ["locale", "theme"]
      },
      "lifecycle": { "allow": true }
    }
  },
  "serverFunctions": {
    "module": "server-functions.js",
    "exports": ["getData", "saveData"]
  },
  "entrypoints": {
    "js": ["/static/feature-my-feature/1.0.0/feature-my-feature.abc123.js"],
    "css": ["/static/feature-my-feature/1.0.0/feature-my-feature.def456.css"]
  },
  "integrity": {
    "/static/feature-my-feature/1.0.0/feature-my-feature.abc123.js": "sha384-...",
    "/static/feature-my-feature/1.0.0/feature-my-feature.def456.css": "sha384-..."
  },
  "signature": {
    "algorithm": "ed25519",
    "keyId": "prod-ed25519-2026-01",
    "signature": "...",
    "signedAt": "2026-03-02T09:12:00.000Z"
  },
  "isolation": {
    "shadowDOM": false
  }
}

Facet feature (reusable CSR module)

json
{
  "id": "feature-summary-module",
  "version": "1.0.0",
  "displayName": "Summary Module",
  "featureType": "facet",
  "channel": "stable",
  "module": {
    "mountExport": "mount",
    "unmountExport": "unmount"
  },
  "entrypoints": {
    "js": ["/static/feature-summary-module/1.0.0/feature-summary-module.abc123.js"]
  }
}

Key fields

FieldRequiredPurpose
idYesUnique feature identifier (kebab-case, prefixed with feature-)
versionYesSemver version
displayNameYesHuman-readable name for admin UI and navigation
featureTypeNodomain (default) or facet (application/module aliases accepted)
channelNoRelease channel: stable, canary, or dev (defaults to stable)
mount.pathPrefixYes for domain; optional for facetURL path prefix (e.g., /my-feature)
mount.domElementIdYes for domain; optional for facetDOM element ID for React mount
routesYes for domain; optional for facetRoutes this feature owns
module.mountExport / module.unmountExportNoModule export names (defaults mount / unmount)
requirements.authRequiredRecommendedIf true, host returns 401 for unauthenticated requests
requirements.minHostVersionRecommendedMinimum host version required
visibilityOptionalTeam-owned visibility metadata (host does not enforce)
sharedRecommendedShared dependencies (React, etc.)
runtime.permissionsOptionalScoped access to host APIs
serverFunctionsOptionalServer-side RPC functions
entrypoints.jsYesClient module entrypoints loaded by the host shell
entrypoints.cssOptionalCSS assets loaded by host shell (or injected into Shadow DOM mode)
integrityYes (published artifacts)SRI map for all declared JS/CSS entrypoints
signatureYes (published artifacts)Manifest signature used by host trust verification
isolation.shadowDOMOptionalCSS isolation via Shadow DOM

Validation rules

The host validates every manifest at load time:

  • id, version (semver), and displayName are required
  • featureType must be domain or facet (legacy application/module aliases are accepted; normalized to domain/facet)
  • channel is optional; when omitted it is normalized to stable
  • mount.pathPrefix and mount.domElementId are required for domain
  • entrypoints.js must be non-empty (entrypoints.css optional)
  • routes must be non-empty for domain
  • Server functions require module or endpoint plus non-empty exports
  • Endpoint must be absolute http/https without credentials
  • Runtime permissions shape is validated
  • requirements.minHostVersion is enforced against the host version

During runtime loading, the host additionally enforces:

  • Manifest signature validity against trusted public keys
  • Non-empty integrity map and SRI hash verification for all entrypoint assets

The runtime host always validates the published artifact manifest, not your source manifest directly.

Visibility

Visibility fields are informational metadata for feature-team logic:

json
{
  "visibility": {
    "featureToggles": ["my-feature-enabled"],
    "tenants": ["hospital-a"]
  }
}

The host does not hide routes based on visibility. If you need gating, enforce it in your feature server/backend logic.

Authentication

Set requirements.authRequired: true to enforce authentication at the route level.

Without an auth signal (bearer token, forwarded token, or cookie), the host returns 401 before your feature code loads.

Auth signals recognized:

  • Authorization: Bearer <token>
  • X-Auth-Request-Access-Token: <token> (ingress-forwarded)
  • Cookie: ... (session-based)