Deploy and roll back a remote
This tutorial deploys one remote to a static registry, promotes it, and rolls it back without a rebuild. It takes about ten minutes and needs no cloud account.
Before you start
You need Node 22.12 or newer, pnpm, and a project made with mfeflow init. The remote must be built, so its dist/ folder holds an mf-manifest.json.
The registry here is a folder on your disk. Section 7 swaps it for an S3 bucket.
1. Tell mfeflow where the registry lives
Every command takes a host and a base URL. The host is where files are written. The base URL is where users will fetch them.
Add both to mfeflow.json, so you do not repeat them:
The examples below pass the same values as flags, so you can try them without editing anything.
2. Preview the deploy
Run a dry run first. It prints the plan and writes nothing:
You should see:
The files go first and the index goes last. The version comes from the remote's package.json.
3. Deploy to staging
Run it again without --dry-run:
You should see:
The warning means the shell's own manifest was not on the host. Shared versions were checked against your workspace instead. To check against the deployed shell, copy its mf-manifest.json to envs/staging/shell/ on the host, or pass --shell-manifest <file>.
4. Promote it to production
Promoting copies the pointer from one environment to another. No files are uploaded:
You should see:
The only file uploaded is the prod index. The gates ran again against prod.
5. Ship a bad version, then roll back
Build version 1.1.0 and deploy it straight to production:
You should see:
Version 1.1.0 turns out to be broken. Roll back:
You should see:
Nothing was rebuilt. Before it moved the index, the command checked that the files of 1.0.0 still exist on the host.
To go further back, pass --to <version>. The version must be in the history that mfeflow status shows. Rolling back again never returns to the bad version.
6. Check what is served
status shows what each environment serves, the version before it, and drift:
You should see:
Now upload a new version without moving the index. This is what --no-publish does:
You should see:
Run status again. It reports the drift:
Drift is also reported when a file in registry/envs/<env>/ names another version than the host serves. Drift is a warning, so status still exits with 0.
7. Use an S3 bucket instead
Point --host at a bucket. AWS S3, Cloudflare R2 and MinIO all work. Settings and credentials come only from environment variables:
Leave MFEFLOW_S3_ENDPOINT out for AWS. Set AWS_SESSION_TOKEN if your credentials are temporary. Credentials are never printed, not in errors and not with --json.
The key needs permission to get and put objects, and to list the bucket. Without the list permission, S3 answers 403 for a missing key and the command stops.
If something fails
A failed gate prints an error and uploads nothing. This is a budget failure:
The command exits with 7. Each gate has its own code:
Other problems have codes too: E506 for the host or base URL, E507 for a missing build, E508 for a version that does not exist, E509 for files missing on the host, E510 for two deploys at once, and E511 for a published version whose content changed.
Two deploys can race on one index. The second one reads the index again and retries once. If it loses again, it stops with E510 and names the time and version the other deploy left. Nothing is overwritten.
Promote and rollback skip the size gate. The size was checked when the version first deployed, and a rollback must work even if today's budget is tighter.
In an incident, rollback --force also skips the schema, route and compatibility checks and prints a warning. It never skips the check that the version's files are on the host.
What you built
A registry you can host anywhere that serves files. It keeps every version, moves one pointer per environment, and goes back by changing that pointer.
How fast a rollback reaches users depends on the host's cache. The index is cached for 60 seconds. GitHub Pages caches every file for 10 minutes, so use a bucket if that is too slow.
On a local file host, a first-time visitor sees the old version about 1 second after rollback exits (median of 5 runs). That is the floor: it has no CDN and no bucket in it, and a returning visitor can wait up to the 60 seconds. How it was measured.
Next
- Every flag is in the CLI reference.
- Use
--jsonin CI. Each command prints one JSON document and exits with a stable code.