# @appshell/runtime

> The shared singleton that delivers a package's runtime configuration to it

Latest version **1.0.0-alpha.91** (published 2026-09-12) · MIT license · 0 weekly downloads

## Install

```sh
npm install @appshell/runtime
pnpm add @appshell/runtime
yarn add @appshell/runtime
bun add @appshell/runtime
```

## Health

**Score 70/100 (B)** — status: active.

Positive: has types; esm support; no vulnerabilities; has provenance; recently updated; high maintenance score.

Warnings: low downloads.

## Facts

| | |
|---|---|
| Version | 1.0.0-alpha.91 |
| Published | 2026-09-12 |
| First published | 2026-08-27 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 0 |
| Unpacked size | 18.5 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Provenance | attested (GitHub Actions) |
| GitHub stars | 0 |
| Author | Robert Hamilton |
| Maintainers | navaris |
| Keywords | module federation, micro-frontends, appshell |

## Links

- npm: https://www.npmjs.com/package/@appshell/runtime
- Repository: https://github.com/appshellhq/appshell
- Homepage: https://github.com/appshellhq/appshell#readme
- Issues: https://github.com/appshellhq/appshell/issues
- npm.io page: https://npm.io/package/@appshell/runtime

## Recent versions

- 1.0.0-alpha.91 (latest) — 2026-09-12
- 1.0.0-alpha.90 — 2026-09-12
- 1.0.0-alpha.89 — 2026-09-12
- 1.0.0-alpha.88 — 2026-09-12
- 1.0.0-alpha.87 — 2026-09-12
- 1.0.0-alpha.86 — 2026-09-12
- 1.0.0-alpha.85 — 2026-09-12
- 1.0.0-alpha.84 — 2026-09-12
- 1.0.0-alpha.83 — 2026-09-12
- 1.0.0-alpha.82 — 2026-09-12
- 1.0.0-alpha.81 — 2026-09-11
- 1.0.0-alpha.80 — 2026-09-11
- 1.0.0-alpha.79 — 2026-09-11
- 1.0.0-alpha.78 — 2026-09-11
- 1.0.0-alpha.77 — 2026-09-11
- … 62 more at https://npm.io/package/@appshell/runtime/versions

## README

# @appshell/runtime

The store that delivers a package's runtime configuration (`vars`) to it.

This is a **shared singleton**. There is exactly one instance per page, held in the
module federation share scope, and both the host and every package must declare it as
such. It replaced `window.__appshell_vars__<scope>`.

Most packages should not import this directly — use `@appshell/runtime/vars` below,
which supplies the scope for you.

## `@appshell/runtime/vars`

The accessor most packages actually want. It reads *this* package's vars, with no scope
to pass and no way to name someone else's:

```ts
import { getVars } from '@appshell/runtime/vars';

const { BACKGROUND_COLOR } = getVars<{ BACKGROUND_COLOR: string }>();
```

It is a subpath rather than a main-entry export for a reason. `AppshellPlugin` compiles
the package's own scope into whatever imports it, and the main entry is the *shared*
module — one instance for the whole page — so a scope baked in there would be one
package's, and every other package would read the wrong vars.

The exact-match share key `'@appshell/runtime'` does not catch `'@appshell/runtime/vars'`,
so each package bundles its own copy of the accessor with its own scope, while the store
they all reach stays the single shared instance.

`getVars` throws `MissingScopeError` when the package was built without `AppshellPlugin`,
since nothing substituted the scope.

## Contract

```ts
setVars(scope, vars); // the host, immediately before loading a remote
readVars(scope); // a package, reading its own configuration
hasVars(scope); // branch instead of catch
```

`@appshell/loader` calls `setVars` before it loads a remote, so a package's vars are in
place before its modules evaluate — including a read at module-eval time.

The first write for a scope wins and is frozen. Re-delivering the identical vars is a
no-op, because the same remote can be mounted more than once; replacing them throws
`VarsConflictError`.

`readVars` throws `MissingVarsError` rather than returning an empty object. A package
that silently renders with no configuration is the failure this replaced.

## What this does and does not fix

Against the global it replaced, it fixes: unbounded, never-cleaned-up keys; silent
cross-package overwrite; the load-order coupling between host and remote; and being
untyped and undiscoverable.

It **does not make a scope's vars private.** Any code on the page can call
`readVars('SomeOtherScope')`, and a package that loads early can squat on a scope that
has not been delivered yet. Nothing short of a separate realm — an iframe, a worker —
would change that, and none of this is a security boundary. Do not put a secret in
`vars`; the registry serves them to the browser in the composition either way.

## Setup

Both sides declare it, or each ends up with its own empty store:

```js
new ModuleFederationPlugin({
  shared: {
    '@appshell/runtime': { singleton: true },
  },
});
```

`AppshellPlugin` fails the build when a package omits it.

---
_Source: https://npm.io/package/@appshell/runtime · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
