native-federation configuration

August 4, 2026 · View on GitHub

< back

native-federation configuration

The @softarc/native-federation-orchestrator library supports a multitude of different configuration settings. The configuration objects are intended to provide more fine-grained control over the behavior of the @softarc/native-federation-orchestrator library.

The configuration is divided into 5 sections

  1. Host related configuration
  2. ImportMap implementations and polyfilling
  3. Logging
  4. Modes (strictness and external resolving settings)
  5. Storage

1. Host configuration

The hostRemoteEntry configuration is meant for adding a host remoteEntry file which receives priority during the determine-shared-versions step. That is, when an external version is defined in the host remoteEntry.json file, it will be guaranteed the shared version. The goal of the cachetag is to avoid caching the remoteEntry.json file.

export type HostOptions = {
    hostRemoteEntry?: string | false | {
        name?: string,
        url: string,
        cacheTag?: string,
        integrity?: string
    },
    manifestIntegrity?: string
}

Options:

OptionDefaultDescription
hostRemoteEntryfalseAllows for the inclusion of a host remoteEntry.json file. The optional integrity field pins the host's remoteEntry.json against an SRI hash (see Security).
manifestIntegrityundefinedSRI hash for the manifest URL passed as the first argument to initFederation. When set, the orchestrator verifies the manifest bytes before parsing.

Example

import { initFederation } from '@softarc/native-federation-orchestrator';

initFederation('http://example.org/manifest.json', {
  hostRemoteEntry: { url: './remoteEntry.json' },
});

Pinning resources with integrity

Manifest entries, the manifest URL itself, and the host remoteEntry can each carry an SRI hash. Verification is opt-in per resource — entries without a hash are fetched unverified, matching the semantics of <script integrity="…">.

initFederation('http://example.org/manifest.json', {
  manifestIntegrity: 'sha384-…',
  hostRemoteEntry: {
    url: './host-remoteEntry.json',
    integrity: 'sha384-…',
  },
});

Per-remote pinning lives in the manifest itself — entries can be either the existing string form or a { url, integrity } object:

{
  "team/mfe1": "https://mfe1.example.org/remoteEntry.json",
  "team/mfe2": {
    "url": "https://mfe2.example.org/remoteEntry.json",
    "integrity": "sha384-…"
  }
}

See Security & Subresource Integrity for the full trust chain (manifest → remoteEntry.json → modules) and the supported hash algorithms.

2. ImportMap configuration

The native-federation library uses importmaps under the hood for module resolving. Since importmaps are a relatively new feature of browsers, it might be a good idea to use a polyfill that is guaranteed to work, also in older browsers. There are 2 options supported: default and es-module-shims.

export type ImportMapOptions = {
    loadModuleFn?: (url: string) => Promise<unknown>
    setImportMapFn?: (importMap: ImportMap, opts?: { override?: boolean }) => Promise<ImportMap>
    reloadBrowserFn?: () => void
    trustedTypesPolicyName?: string | false
}

Options:

OptionDefaultDescription
setImportMapFnreplaceInDOM("importmap")The function that adds the importmap to the host, by default this is the DOM.
loadModuleFnurl => import(url)This function can mock or alter the 'import' function, necessary for libraries that shim the import function.
reloadBrowserFn() => {window.location.reload();}This function can mock or alter the "reload browser" behavior that is triggered when SSE is enabled and an user rebuilds a remote.
trustedTypesPolicyName"nfo"Name of the Trusted Types policy that wraps import-map content and dynamic-import URLs in the default setImportMapFn and loadModuleFn. Pass false to opt out. No effect on browsers that do not support Trusted Types.

Example

import 'es-module-shims';
import { initFederation } from '@softarc/native-federation-orchestrator';
import { useShimImportMap, useDefaultImportMap, replaceInDOM } from '@softarc/native-federation-orchestrator/options';

initFederation('http://example.org/manifest.json', {
  // Option 1: Using es-module-shims
  ...useShimImportMap({ shimMode: true }),

  // Option 2: Using the default importmap
  ...useDefaultImportMap(),

  // Option 3: Custom properties
  loadModuleFn: (url: string) => { return customImport(url); },
  setImportMapFn: replaceInDOM('<importmap-type>'),

  // Option 4: rename the Trusted Types policy to match a stricter CSP allowlist
  trustedTypesPolicyName: 'my-app-nfo',
});

See Security — Trusted Types for the recommended CSP header and how the orchestrator interacts with a host-defined policy.

3. Logging configuration

Allows for the configuration and specificity of logging. Additionally, a custom logger can be defined.

export type LoggingOptions = {
    logger?: Logger,
    logLevel?: "debug"|"warn"|"error",
    sse?: boolean
}

Options:

OptionDefaultDescription
loggernoopLoggerThe logger is an object that returns a callback per logging type. This way, a custom log implementation can be provided next to the 2 integrated loggers noopLogger and consoleLogger.
logLevel"error"There are currently three loglevels, every loglevel will allow the logging of the specified level including all levels with a higher priority, e.g. warn will allow the logging of warn and error.
ssefalseThe SSE is a debug feature that listens for rebuilds of the remotes, and reloads the page if a rebuild occurs.

Example

import { initFederation } from '@softarc/native-federation-orchestrator';
import { noopLogger, consoleLogger } from '@softarc/native-federation-orchestrator/options';

initFederation('http://example.org/manifest.json', {
  logLevel: 'debug',

  // Option 1: noopLogger
  logger: noopLogger,

  // Option 2: consoleLogger
  logger: consoleLogger,
});

4. ModeConfig

The mode config focusses on the way the library behaves, especially when resolving shared externals. The options are meant as hyperparameters to tweak the strictness of native-federation.

export type ModeOptions = {
  strict?: boolean | {
    strictRemoteEntry?: boolean;
    strictExternalCompatibility?: boolean;
    strictExternalSameVersionCompatibility?: boolean;
    strictExternalVersion?: boolean;
    strictImportMap?: boolean;
    strictEntryPointCoverage?: boolean;
  };
  profile?: {
    latestSharedExternal?: boolean;
    skipInvalidExternalVersions?: boolean;
    scopeUncoveredEntrypoints?: boolean;
    overrideCachedRemotes?: 'always' | 'never' | 'init-only';
    overrideCachedRemotesIfURLMatches?: boolean;
    cacheTag?: string;
  };
  feature?: {
    convertFlatSharedInfo?: boolean;
    useAutoExternalPooling?: boolean;
  };
};

Options:

The strictness part will define how the orchestrator behaves when an unexpected or erronous situation occurs. The profile focusses on how aggressive the orchestrator should handle caching.

Strictness

OptionDefaultDescription
strictfalseWhen true, the init function will throw an error if anything goes wrong during initialization
strict.strictRemoteEntryfalseWill throw an error if anything is wrong with a fetched remoteEntry.json. When false, the remote will be skipped if something goes wrong.
strict.strictExternalCompatibilityfalseWill throw an error if any of the shared externals are incompatible with other shared external versions. If the value is false, the external will be set to "scoped" instead of "shared".
strict.strictExternalSameVersionCompatibilityfalseThis is an extreme niche edge case. Will throw an error if the external's shared version (e.g. rxjs version 1.2.3) was already processed and cached, but the to-be-processed versionRange is different than the cached versionRange. This hypothetically could cause an issue when the "chosen" version was removed and this fallback was chosen as the new shared version since it supports a different version range according to the metadata
strict.strictExternalVersionfalseWill throw an error if the version of an external is not valid semver or missing. When false, the external is instead coerced to the smallest version that matches its requiredVersion range — unless profile.skipInvalidExternalVersions is enabled, in which case the external is skipped. Takes precedence over profile.skipInvalidExternalVersions.
strict.strictImportMapfalseWill throw an error if anything goes wrong during the buildup of the importMap. (If something is wrong with the cached externals or the cache is corrupt).
strict.strictEntryPointCoveragefalseWill throw an error if a shared external cannot be served coherently — i.e. a remote on another version declares a secondary entrypoint no copy of the shared version contains ("entrypoint tearing"). If the value is false, the entrypoint is served from the consuming remote's own build (self-fill, with a warning) so nothing is lost, unless profile.scopeUncoveredEntrypoints is enabled, in which case the uncovered copy is scoped instead. Copies of the shared version itself always merge, so this never fires within one version. See Entrypoint coverage and tearing.

Profiles

OptionDefaultDescription
profile.latestSharedExternalfalseWhen enabled, the version resolver will prioritize using the latest version of a shared external over the most optimal version.
profile.skipInvalidExternalVersionsfalseWhen enabled, an external whose version is not valid semver or missing is skipped (not added to storage) instead of being coerced to the smallest version of its requiredVersion range. Has no effect when strict.strictExternalVersion is set, which throws instead.
profile.scopeUncoveredEntrypointsfalseWhen enabled, a remote copy on another version whose secondary entrypoints the shared version cannot cover is split out into a "scoped" version and serves its whole entries bunch from its own build, instead of tearing the package across two builds. Sharing continues for the copies the shared version does cover. Like strict.strictEntryPointCoverage, this only governs tears between versions: copies of the shared version always merge their entrypoints. Has no effect when strict.strictEntryPointCoverage is set, which throws instead.
profile.overrideCachedRemotesinit-onlyWhen enabled, the library will override the cached remotes. The default behavior is to check if the remoteName is in the cache and the remoteEntry url differs from cached remoteEntry url (scopeUrl + "remoteEntry.json) . Available options are never, init-only and always
profile.overrideCachedRemotesIfURLMatchesfalseWhen enabled, the library will override the cached remote, even if the remoteName already exists in cache and the remoteEntry.json URL matches the cached remoteEntry.json url.
profile.cacheTagundefinedWhen set, the given value is appended as a ?cacheTag=<value> query param to every remoteEntry.json request, letting you bust HTTP caches across all remotes at once. The host's own hostRemoteEntry.cacheTag takes precedence for the host remoteEntry when both are set.

Features

OptionDefaultDescription
feature.convertFlatSharedInfofalseOpts into runtime densification of remoteEntry shared externals. Core v4.3.0 emits DenseSharedInfo (a per-package entries map covering primary and secondary entrypoints) natively; those pass through unchanged. For older/flat remote builds that emit one flat SharedInfo per entrypoint, enabling this groups secondary entrypoints under their parent package (by npm scope) so they resolve as one shared external.
feature.useAutoExternalPoolingfalseWhen enabled, shared externals are grouped into pools by their npm scope (@framework/core, @framework/common → pool framework) so that no remote draws a coupled family from builds that never shipped it together: a remote either takes the whole family from one build, or serves the whole family from its own. Buys coherence at a possible cost in downloads, never a reduction. Unscoped packages are not auto-pooled; a remote can also opt a specific external into a pool with a pool tag on its shared external regardless of this flag. See Dependency Pooling.

Example

import { initFederation } from '@softarc/native-federation-orchestrator';
import { defaultProfile, cachingProfile } from '@softarc/native-federation-orchestrator/options';

initFederation('http://example.org/manifest.json', {
  strict: true, // All settings to strict: true
  profile: cachingProfile, // { latestSharedExternal: false, skipInvalidExternalVersions: false, overrideCachedRemotes: 'never', overrideCachedRemotesIfURLMatches: false }
});

5. StorageConfig

The library stores the current state by default in the globalThis object, it is possible to provide a custom storage or switch to localStorage or sessionStorage.

type StorageOptions = {
    storage?: StorageEntryCreator,
    clearStorage?: boolean,
    storageNamespace?: string,
}

Options:

OptionDefaultDescription
storageglobalThisStorageEntryAllows the provision of a custom storage implementation.
clearStoragefalseWhen enabled, the initFederation function will clear the current cache/storage before initializing the remoteEntries.
storageNamespace"__NATIVE_FEDERATION__"The namespace under which the cache will be stored. e.g. remotes will be stored under __NATIVE_FEDERATION__.remotes in localStorage

Example

import { initFederation } from '@softarc/native-federation-orchestrator';
import {
  globalThisStorageEntry,
  localStorageEntry,
  sessionStorageEntry,
} from '@softarc/native-federation-orchestrator/options';

initFederation('http://example.org/manifest.json', {
  clearStorage: true,
  storageNamespace: '__custom_namespace__',

  // Option 1: globalThis
  storage: globalThisStorageEntry,

  // Option 2: localStorage
  storage: localStorageEntry,

  // Option 3: sessionStorage
  storage: sessionStorageEntry,
});