Migrate an existing project
Convert an sfdx project with package directories into the sfpm workspace layout.
Use this page when your project already has an sfdx-project.json. The
migration reads that file and writes workspace files next to it. Your metadata
stays where it is.
Before you start
- Commit your current state, or work on a branch. The migration writes files into your project.
- Check the
packageDirectoriesinsfdx-project.json. sfpm migrates only the entries that have both apackagename and aversionNumber. Other entries are skipped, and the migration does not report them.
Run the migration
sfpm project init turbo --migrate --npm-scope @myorg| Flag | Description |
|---|---|
--migrate, -m | Migrate from the existing sfdx-project.json. Without this flag, the command scaffolds a new workspace. If the file exists and you run interactively without this flag, sfpm asks whether to migrate instead. |
--npm-scope <scope> | npm scope for package names, for example @myorg. sfpm adds the @ if it is missing. Without the flag, sfpm reads the scope from the root package.json name or the .npmrc registry line. A non-interactive run fails when no scope is found. |
--package-manager <pm> | pnpm (default), npm, or yarn. This guide covers pnpm workspaces only. |
--yes, -y | Skip the prompts and use the defaults. |
--json | Print the result as JSON. Like --yes, this skips the prompts. |
Do not pass --workspace-dir. The flag is accepted, but the workspace it
produces cannot find its packages, so it does not build. Migrate without it.
Each package keeps its original directory and gets its own package.json
there. If you run the migration interactively without --yes, it asks
where package directories should live; choose "Keep original paths", not
"packages/" or "Custom..." (those are the same broken layout as passing
--workspace-dir directly).
What the migration writes
Project root
package.jsonis created, or updated if it exists. The root is marked private,turbois added as a dev dependency, and thesfpm:build,sfpm:deploy, andsfpm:installscripts are added. Those scripts run through Turborepo.pnpm-workspace.yamllists the directories that hold packages. Directories under the same parent collapse into one glob, such aspackages/*.turbo.jsondefines thesfpm:build,sfpm:deploy, andsfpm:installtasks. Build output goes todist/, and build results are cached. The migration does not ask for input directories, so the build inputs use Turborepo's default (all git-tracked files)..gitignoregetssfdx-project.jsonanddistadded, if they are not already listed.
The root package.json also gets a sfpm:sync script that runs sfpm sync.
That command does not exist. Change the script to run sfpm project sync.
Each package
For each package in sfdx-project.json, the migration writes a package.json:
- Location. The file goes in the package's existing directory, next to its source.
nameis<npm scope>/<package name>.versioncomes fromversionNumber. A build segment other thanNEXTor0is kept as a prerelease suffix. For example,1.2.0.LATESTbecomes1.2.0-LATEST. Check the version after migrating.sfpm.packageTypeisunlockedunless thepackageDirectoriesentry has atypekey.sfpm.pathis the source path relative to the package directory. It is left out when the source sits at the package root.sfpm.packageIdis copied frompackageAliaseswhen the alias is a Package2 ID.- Dependencies on other migrated packages become
workspace:^<version>. - Scripts
sfpm:build,sfpm:deploy, andsfpm:installrunsfpm build,sfpm deploy, andsfpm installfor that package with--turbo.
If a package.json already exists in the target directory, the migration
merges into it. Existing scripts and dependencies entries stay, except for
the sfpm script names. Top-level fields with the same names, such as name,
version, and sfpm, are replaced.
Every package is written as unlocked unless its packageDirectories entry
has a type key. Open each package.json and set packageType to source
or data where that is the real type.
What the migration does not do
- It does not move or copy metadata. The source stays where it is. Each
package's
sfpm.pathpoints at its existing source directory. - It does not delete or rewrite
sfdx-project.json. The nextsfpm project syncrewrites it. If git already tracks the file, it stays tracked until you rungit rm --cached sfdx-project.json. - It does not carry over the namespace. If a package has a namespace, add
"namespace": "<prefix>"to that package'ssfpmblock.
After the migration
pnpm install
sfpm project sync
git statusReview each package.json, paying attention to packageType, version, and
sfpm.path. Commit the workspace files and the package.json files. Do not
commit sfdx-project.json, because it is generated.
For the flags on each command, see the project commands reference.