CLI reference
This page lists every command, flag and exit code of the mfeflow command line. It matches mfeflow --help for version 0.4.0. For task-based help, use the guides.
In a generated project, run commands as pnpm mfeflow <command>. To create a project, use pnpm create mfeflow, which runs init.
Run the command with --help for the options and examples of one command.
Commands
This release has no command to remove a feature.
An unknown command exits with code 2 (E107).
Global options
Every command accepts these.
init
Creates a project.
Feature names accepted by --features: lint-oxlint, url-factory, env-t3, testing, analytics-gtm, telemetry-otel, event-bus, route-factory, http, theming, i18n, tailwind, ui-shadcn, forms, data-react-query, analytics-clarity, storybook, ci-github, git-hooks, commit-prompt.
With --topology polyrepo, dir is a folder that holds one git repo per platform, shell and remote. --features goes to the shell and the remote repos. ci-github and env-t3 are refused, and no feature is on by default. The result lists each repo under repos. See One repo per team.
adopt
Sets up mfeflow in a project that already uses Module Federation. The tutorial is in Bring an existing Module Federation app.
It reads the build config as source text and writes mfeflow.json, one mfeflow.app.json per app, registry/envs/<env>/<remote>.json for dev, staging and prod, and adds @mfeflow/runtime to each shell's package.json. It never edits a build config file. It prints a line to paste into your shared list instead.
In a terminal the command asks once before it writes. Without a terminal, and without --yes or --dry-run, it exits with code 2 and writes nothing. The files are written all or nothing.
If mfeflow.json already exists the command stops with E123. A folder with no shell stops with E124. Parts of the config that could not be read, or have no home in mfeflow, are printed as not carried over: with a reason. They do not change the exit code: a partial adoption exits 0 and the plan carries warnings.
--json prints { ok, command: "adopt", dryRun, root, scope, apps[], notAdopted[] (dir, file, field, reason), buildConfig[], snippet, next, plan, written, installed, diff }.
add
Adds an app, a team repo, features or an env key. Five forms:
add team-repo runs in the shell repo of a polyrepo. It creates ../<name> as a git repo with the first-party features the shell has, then adds a route, staging and prod registry entries and a dev server entry to the shell. It writes the new repo first, so a failure leaves no folder. Run it elsewhere and it exits with code 2 (E107).
A feature from a registry is written only after a yes at the prompt, or with --yes. Without a terminal, --yes is required.
features
Lists and searches features from mfeflow and every configured registry.
The search matches name, description or keywords. A registry that cannot be read is reported on stderr and the others are still listed. The exit code stays 0.
registry
Manages third-party feature registries in mfeflow.json, or builds one to host.
The URL must be https. Plain http is accepted for loopback hosts only: localhost, 127.0.0.1 and [::1]. The namespace @mfeflow is reserved.
The build action lists every problem and writes nothing if there is one (E404).
upgrade
Moves the project to the version of mfeflow you run. It never asks npm for a newer one. The tutorial is in Versions and upgrades. It does not work in the repos of a polyrepo yet and exits with code 2 (E107) without writing.
A generated file you did not edit is replaced and a new file is created. package.json, pnpm-workspace.yaml and turbo.json only get small edits. Files the new version no longer makes, and files you deleted, are listed and left alone. A file you changed is offered only when the new version generates something different from the old one. It is never written unless you accept it.
Without a terminal there is nobody to ask. A changed file with no decision stops the run before anything is written, with E604 and exit code 8, even with --yes. A --dry-run never fails that way: it prints everything and exits 0. A symlink is reported and never written over, with or without --accept all. So is a file under a symlinked folder: every part of the path from the project root down is checked. A symlink needs no decision and never blocks a run.
A feature from a registry is applied only after you confirm in a terminal, or pass --yes without one. The content of each registry feature is compared with the hash in mfeflow.json. If the registry now serves other bytes for the same version, the run stops with E406. Pass --accept-changed-content to take them, or name the features, as in --accept-changed-content @acme/hello. Repeat the flag to add names. A name that is not an installed feature, or an empty =, is E107. The new hash is saved even when no file changes. A feature with no recorded hash is shown as first seen and its hash is recorded. The files are written all or nothing, and the install runs in the same step.
integrity maps each registry feature to verified, first-seen or accepted-changed. changedValues is the part of lostKeys that the new version has with another value.
--json prints { ok, command: "upgrade", dryRun, root, from, fromSource, to, upToDate, replaced, created, edited, diverged: [{ path, reason, decision, lostKeys, changedValues, diff }], integrity, missing, removed, migrations, plan, written, installed, diff }.
doctor, validate and check-compat
doctor --fix repairs a missing workspace version (E111) and missing registry entry files (E114). Add --dry-run to see the diff first.
doctor --against <url|file> runs every check and takes the shell for the compatibility check from a deployed shell, as check-compat --against does (the list below says what it accepts). Use it in a remote repo whose shell lives elsewhere. With --against, the "shell is not in this repo" warning does not appear. Without it, a repo that has remotes but no shell prints shell is not in this repo, run \mfeflow doctor --against <url|file>`. A source that cannot be read is E307 and exits 5, as in check-compat. A skewed shared version is E302 and also exits 5. The code follows the errors in the report, so a project error (E1xx) in the same run exits 3 instead. With --json, against` holds the source you passed, with any token in a URL hidden.
check-compat
Checks each remote's shared ranges against the shell it runs in. By default it reads the shell's versions from node_modules in this repo.
--against takes one of three things:
- A registry index for an environment. The shell's
mf-manifest.jsonis read fromshell/mf-manifest.jsonbeside it. - A deployed shell
mf-manifest.json. - A local file of either kind.
Every remote in this repo is then checked against the versions the shell shares. A remote that needs a React the shell does not provide is an error (E302) and exits with code 5.
A URL must be https. Plain http is allowed for localhost only. The answer may not be larger than 1 MB, and a redirect to a private address is refused. A source that cannot be read is E307.
Some versions cannot be compared before install, such as workspace:* or catalog:. Each one is a warning, not an error.
If the shell is not in this repo and you pass no --against, the check cannot compare anything. It does not pass silently. It prints this warning:
A warning does not change the exit code, as with every other check. The command exits 0 unless there is an error. With --json, against holds the source you passed, with any token in a URL hidden.
budget
Measures the built JavaScript of the shell and each remote against the cost model. Build first.
See CI and budgets for what it checks and The cost model.
dev
Runs the shell and every remote with a dev registry that follows the project. In the shell repo of a polyrepo it runs the shell only, and the registry lists the remotes in devRemotes of public/config/runtime-config.dev.json.
Ctrl+C stops everything and exits with code 130. See Develop locally.
deploy, promote, rollback and status
A walk-through with output is in Deploy and roll back a remote.
S3 settings come from MFEFLOW_S3_ENDPOINT, MFEFLOW_S3_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and AWS_SESSION_TOKEN, and are never printed. --dry-run prints the plan as data and writes nothing. Without --yes, a terminal asks before anything moves. A failed gate exits with 7 and one of E501 to E505. The other deploy errors are E506 to E512.
--json prints { ok, command, dryRun, env, fromEnv, host, remote, version, servedBefore, published, previous, rolledBackFrom, uploads, uploaded, skipped, localEntry, warnings, findings } for the first three, with index added for a dry run. status prints { ok, command: "status", host, envs: [{ env, published, generatedAt, remotes }], findings }. A successful deploy, promote or rollback also writes registry/envs/<env>/<remote>.json, so git records what is served. Not for dev: mfeflow dev reads that folder.
Server mode
Set MFEFLOW_REGISTRY_URL, or pass --registry-url, and deploy, promote, rollback and status talk to a registry server instead of writing a static index. Without it nothing changes.
In server mode deploy still uploads the build to --host first, because the server never stores files. Then it asks the server to move the pointer. promote --percent sends the rollout with the promote, so it needs promote on the target and read on the source, and it is audited as a promote. status needs --env outside a project, and shows kills and rollouts when a token is set.
--json and --dry-run work as in static mode. A dry run reads the index and sends nothing, so the server's own checks do not run. Server answers map to the same codes: a missing version or rollout is E508, a changed published version is E511, a missing build file is E509, a lost race is E510, and an unreachable server, a bad token or a missing token is E506. All exit with 7.
Exit codes
For the four check commands, the exit code is the lowest code among the errors found. Warnings do not change it. Every error has a code and a page. See Error codes.
Output and exit codes
With --json, a command prints one JSON document and nothing else. An error prints a failure document:
The success documents have these shapes. Each has ok and command.
The plan in the init and add output lists features, changes (path and action), dependencies, scripts and warnings. Output shapes are part of the public API. See Versions and upgrades.