Project commands
Check the project setup, scaffold and sync the workspace, create packages, and bump versions.
An sfpm project is a pnpm workspace. Each package lives in its own directory
with a package.json, and the sfpm field in that file is the source of
truth for the package's type, source path, and options. sfdx-project.json is
generated from those files by sfpm project sync, and is replaced the next
time you run it. Change the package's package.json or sfpm.config.ts
instead of editing sfdx-project.json by hand.
Command summary
| Command | Description |
|---|---|
sfpm project | Shows the package dependency tree. |
sfpm project init | Checks git, the git remote, sfdx-project.json, and package definitions. Exits with code 1 on failure. |
sfpm project init turbo | Scaffolds a new workspace, or migrates an existing sfdx-project.json into one. |
sfpm project sync | Generates sfdx-project.json from the workspace package.json files. |
sfpm project version bump | Bumps package versions in the workspace. |
sfpm package create | Scaffolds a new package directory with its package.json. |
sfpm add | Adds packages as dependencies with pnpm. |
sfpm project
Prints the dependency tree for every package in the project, with a legend for package types.
| Flag | Default | Description |
|---|---|---|
-p, --path | off | Shows each package's directory next to its name. |
sfpm project init
Checks the project setup and reports each check as passed or failed:
- The project is a git repository (a
.gitdirectory exists). - The git repository has an
originremote. sfdx-project.jsonexists.- At least one package is defined.
The command exits with code 1 when any check fails.
| Flag | Default | Description |
|---|---|---|
-f, --fix | off | Prints the suggested fix for each failed check. It does not change any files. |
Run sfpm project sync before sfpm project init if sfdx-project.json does
not exist yet. The --fix flag only prints suggestions. Make the change
yourself, for example with git init or git remote add origin <url>.
sfpm project init turbo
Creates the workspace files for a new project, or migrates an existing
sfdx-project.json into package directories. The command writes the root
package.json, pnpm-workspace.yaml, and turbo.json, adds an
sfdx-project.json entry to .gitignore, and creates a package.json for each
package. It then prints the files it created and modified.
| Flag | Default | Description |
|---|---|---|
-m, --migrate | off | Migrates an existing sfdx-project.json into workspace packages. Without this flag, an interactive run asks when it finds one. With --yes, the command does not ask, so it scaffolds unless --migrate is set. |
--npm-scope <scope> | detected | npm scope for package names, such as @myorg. sfpm reads it from the root package.json name or the .npmrc registry scope when it can. If it cannot detect one, interactive runs prompt for it and --yes or --json runs fail. |
--package-manager <pm> | pnpm | Package manager for the workspace. Use pnpm. The flag also accepts npm and yarn, which this documentation does not cover. |
--workspace-dir <dir> | none | Directory to group migrated packages under, such as packages. Used with migration only. Do not use this flag: the workspace it produces cannot find its packages. See Migrate an existing project. |
-y, --yes | off | Skips prompts and uses defaults. |
--json | off | Prints the result as JSON. |
For a fresh scaffold in an interactive run, the command asks which top-level
directories hold build source. These become the Turborepo cache inputs. The
defaults are force-app, src, data, and main, when they exist.
After init turbo, install dependencies and generate sfdx-project.json:
pnpm install
sfpm project sync
turbo run sfpm:buildThe command's printed next steps may show sfpm sync --turbo. That command does
not exist. Run sfpm project sync.
sfpm project sync
Reads the sfpm field and other metadata from each package's package.json,
then writes sfdx-project.json. Project-level settings come from
sfpm.config.ts: sfdcLoginUrl, sourceApiVersion, and
sourceBehaviorOptions.
sfpm.config.ts also has a top-level namespace field, but sfpm project sync does not currently forward it anywhere. The only namespace setting
that has any effect is a per-package sfpm.namespace field in that
package's own package.json.
Run sfpm project sync after you add or remove a package, change a package's
package.json, or change sfpm.config.ts. This command has no --turbo flag.
| Flag | Default | Description |
|---|---|---|
--api-version <value> | sourceApiVersion from sfpm.config.ts | Overrides the Salesforce API version for this run, such as 63.0. |
--json | off | Prints the result as JSON. |
sfpm project version bump
Bumps package versions in the workspace. In a workspace project, the new
version is written to each affected package's package.json.
Choose one bump type. If you pass none, the command uses a patch bump.
| Flag | Description |
|---|---|
-M, --major | Increments the major version. |
-m, --minor | Increments the minor version. |
--patch | Increments the patch version. This is the default. |
-v, --versionnumber <value> | Sets an exact version. |
Choose which packages to bump. The first selector that applies wins, in this
order: --package, --targetref, --targetorg. If none applies, every package
is bumped.
| Flag | Description |
|---|---|
-p, --package <name> | Bumps one package. |
-r, --targetref <ref> | Bumps packages changed since a git ref, such as main. |
-o, --targetorg <alias> | Compares against the package versions installed in this org. |
-a, --all | Bumps every package. Same as passing no selector. |
Other flags:
| Flag | Default | Description |
|---|---|---|
--dryrun | off | Prints the planned changes and writes nothing. |
-f, --projectfile <path> | sfdx-project.json | Path to the project file. Its directory is used as the project root. The default uses the current directory. |
Dependent packages are updated too. The command prints each package's old and new version, and then the dependent packages that changed as a result.
sfpm project version bump --package my-package --minor --dryrun
sfpm project version bump --targetref mainsfpm package create
Creates a package directory named after the package, with a package.json
and an empty source directory. The package.json gets an sfpm field with the
package type.
sfpm package create always creates the new package directory at the
project root, regardless of any workspace-dir prefix used elsewhere in the
workspace. In a workspace scaffolded by sfpm project init turbo (which
only looks for packages under packages/*), a package created this way is
never discovered. Until this is fixed, create the package by hand instead:
add a packages/<name>/package.json with an sfpm field, matching your
other packages, then run sfpm project sync.
| Flag | Default | Description |
|---|---|---|
-n, --name <name> | none | Package name without the npm scope. Required with --json. Prompted otherwise. |
-t, --type <type> | unlocked | unlocked, source, or data. Prompted otherwise. |
-s, --scope <scope> | none | npm scope, such as @myorg. Without a scope, the package name has no scope. |
-p, --path <path> | . | Salesforce source path inside the package directory, such as force-app. Use . when the source is at the package root. |
-d, --devhub <username> | none | DevHub for creating the Package2 container of an unlocked package. Without it, interactive runs ask whether to create one, and --json runs create none. |
--org-dependent | off | Creates an org-dependent unlocked package. Applies to unlocked packages only. |
--json | off | Runs without prompts and prints the result as JSON. |
If no Package2 container is created, the sfpm.packageId field in the
package's package.json stays empty. Add the ID after you create the package
in your DevHub.
sfpm package create --name my-package --type unlocked --scope @myorg --devhub my-devhub
sfpm package create --name my-data --type data --scope @myorg --jsonAfter creating a package, run pnpm install so the workspace links the new
package.
sfpm add
Runs pnpm add with the package names you pass, in the project root. After the
install, it warns about any added package whose package.json has no sfpm
field, because those packages are not sfpm packages.
sfpm add @myorg/my-package
sfpm add @myorg/package-a @myorg/package-bNext steps
Build the packages you created or migrated with the build command. Deploy or install them with the deploy and install commands.