MainSDK
Search⌘K
Interfaces

Developer experience

Upgrades

upgrade

Move every MainSDK package to a new release together with one command that applies the release's codemods and main.yaml moves, runs sync, check and your tests, and opens a pull request; and find out when a security release is not installed.

Building for 0.5ships as a beta APIPhase 1 · Core, public betaSpec upgradeFree in your app, Apache-2.0

Status Status is where the work is: Planned (in a milestone, not started), Building (tickets in progress), Preview (usable, may change), then the stability it ships at.

Stability The promise an interface ships with.

  • Stable Follows semantic versioning; breaking changes need a new major, 12 months of overlap and a codemod.
  • Beta Usable in production; may change before it becomes stable.
  • Experimental May change or go away; needs an explicit opt-in in main.yaml.
Stability levels
Updated 2026-10-28

mainsdk upgrade moves an app to the next MainSDK release with one command, so apps built on a 0.x API are not stranded. It runs in your own tooling and is free.

It moves every mainsdk and @mainsdk/* package together, applies the release's codemods and main.yaml key moves, refreshes main.lock, runs check and your tests, and lists the few steps that need a person. During 0.x a minor release may change an API.

At a glance

Calls

  • mainsdk upgrade
  • mainsdk upgrade --check

Guarantees

Whatever the driver.

  • Dry run by default for planning; applying needs a clean git tree and works on a new branch
  • Every MainSDK package moves together to one exact version
  • Codemods run on your own TypeScript compiler, are idempotent and never touch node_modules
  • Steps a person has to do are listed with file and line
  • The default branch never moves

Drivers

2 drivers. Select one to see its line in main.yaml.

main.yamlnpm registry and private registries from .npmrc (default)
upgrade:
  driver: npm-registry

Change this one line to swap providers; your calls stay the same.npm registry and private registries from .npmrc integration

Codes

CodeWhere it appearsMeaning
MAIN-UPGRADE-0002Checkmainsdk check, before deployMainSDK packages are at different versions in the workspace; they move only together
MAIN-UPGRADE-0005Checkmainsdk check, before deployA release marked security is newer than the installed version
MAIN-UPGRADE-0010Checkmainsdk check, before deployA release's API report has a removed or changed export with no upgrade note entry, or an entry's codemod has no fixture
MAIN-UPGRADE-0001RuntimeError responses and logsThe git working tree has uncommitted changes, or the folder isn't a git repository; nothing was changed
MAIN-UPGRADE-0003RuntimeError responses and logsA codemod couldn't run (no typescript in the app, or a file didn't parse); it is listed as a manual step with file and line
MAIN-UPGRADE-0004RuntimeError responses and logsThe registry couldn't be reached, so the target version is unknown; nothing was changed
MAIN-UPGRADE-0006RuntimeError responses and logsAfter the upgrade, the install, sync, check or the app's tests failed; the branch is kept and the pull request is a draft listing the failures

Features

Nothing here has shipped yet. Each feature lands in its phase; the spec ticket builds it.

FeaturePhaseMilestoneSpec ticket
upgrade --plan from the registry and the release notesPhase 10.5upgrade#plan
BranchPhase 10.5upgrade#apply
Idempotent codemods and main.yaml key movesPhase 10.5upgrade#codemods
SyncPhase 10.5upgrade#verify-pr
upgrade --check for security releasesPhase 10.5upgrade#security-check
Release gate for notes and codemod fixturesPhase 10.5upgrade#notes-gate

Quick start

bash
npx mainsdk upgrade --to latest --plan    # what would change; nothing is written
npx mainsdk upgrade --to latest           # branch, bump, install, codemods, sync, check, tests, pull request
npx mainsdk upgrade --check               # exit 1 when a security release is not installed

--plan reads the installed version from your lockfile and the target from the registry's dist-tags. It prints, in version order, every change between the two: each codemod, each manual step, each main.yaml move that applies to your file, and every call site of a call the target removes. With --to <exact version> and release notes the installed CLI already has, it plans offline.

Configuration

upgrade has no main.yaml section. It takes command-line options.

OptionMeaning
--to <version> or --to latestThe target release (default latest, from the registry's dist-tags)
--planPrint every change and write nothing
--checkExit 1 when a security release is not installed
--jsonMachine-readable output

What you get

  1. Refuses a dirty working tree or a folder outside git (MAIN-UPGRADE-0001) and changes nothing.
  2. Creates the branch chore/upgrade-mainsdk-<version> from the current commit.
  3. Sets every MainSDK dependency in every workspace package.json to the exact target version, and runs your package manager's install (the one your lockfile names).
  4. Runs the newly installed CLI as mainsdk upgrade --continue --from <old version>, so the target release's notes and codemods do the rest: the main.yaml moves in every layer file (comments and order kept), then the codemods.
  5. Runs sync, check and your test script, commits once with the versions, codemods and manual steps in the message, and opens a pull request. A failure gives MAIN-UPGRADE-0006, keeps the branch and opens a draft that lists each failure. The default branch never moves.

Codemods

Codemods run on the TypeScript compiler API loaded from your own typescript; the CLI bundles no compiler. Each is idempotent and touches only your source, never node_modules or generated output. With no typescript, or a file that doesn't parse, the change becomes a manual step with file and line (MAIN-UPGRADE-0003).

Security releases

mainsdk upgrade --check exits 1 with MAIN-UPGRADE-0005 when the registry has a release newer than yours whose notes say security: true. The answer is cached for 24 hours under .mainsdk/cache/. Offline it reports MAIN-UPGRADE-0004 as info and exits 0. mainsdk check shows the cached result and never calls the network for it, and reports MAIN-UPGRADE-0002 when your MainSDK packages are at different versions.

Release notes

Each release of the CLI package ships upgrade/<version>.json for itself and every earlier version:

json
{
  "version": "0.6.0",
  "security": false,
  "changes": [
    { "id": "share-expires-in", "kind": "breaking", "summary": "share() takes expiresIn instead of expires", "codemod": "share-expires-in" },
    { "id": "realtime-base", "kind": "manual", "summary": "Move custom realtime paths under realtime.base", "steps": "Set realtime.base to the path your proxy forwards" }
  ],
  "main-yaml": [ { "from": "share.expiry", "to": "share.max-expiry" } ]
}

kind is breaking (with a codemod), manual (with steps) or info. A change may list calls it removes and exports it changes. In the MainSDK repository the release gate fails with MAIN-UPGRADE-0010 when a removed or changed export has no breaking or manual entry, or a codemod has no passing before/after fixture.

Errors and checks

CodeWhen
MAIN-UPGRADE-0001The working tree is dirty or the folder is outside git; nothing changes
MAIN-UPGRADE-0002Your MainSDK packages are at different versions (mainsdk check)
MAIN-UPGRADE-0003A codemod could not run (no typescript, or a file that doesn't parse); it becomes a manual step
MAIN-UPGRADE-0004Offline during upgrade --check (info; exits 0)
MAIN-UPGRADE-0005A security release newer than yours is not installed
MAIN-UPGRADE-0006A step failed after the bump; the branch is kept and a draft pull request lists each failure
MAIN-UPGRADE-0010In the MainSDK repository, a removed or changed export has no release-note entry, or a codemod has no passing fixture

Each code's cause and fix is in check codes.

Swapping drivers

upgrade has no driver. It reads the installed version from your lockfile and the target from the registry's dist-tags, and uses the package manager your lockfile names.

Testing

upgrade runs your own test script after the bump. Run npx mainsdk upgrade --to latest --plan first to see every change without writing anything; with an exact --to version and release notes the installed CLI already has, the plan runs offline.

Next

Was this page helpful?

↑↓ moveEnter openEsc close

Not decided yet