sfpm
CLI reference

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

CommandDescription
sfpm projectShows the package dependency tree.
sfpm project initChecks git, the git remote, sfdx-project.json, and package definitions. Exits with code 1 on failure.
sfpm project init turboScaffolds a new workspace, or migrates an existing sfdx-project.json into one.
sfpm project syncGenerates sfdx-project.json from the workspace package.json files.
sfpm project version bumpBumps package versions in the workspace.
sfpm package createScaffolds a new package directory with its package.json.
sfpm addAdds packages as dependencies with pnpm.

sfpm project

Prints the dependency tree for every package in the project, with a legend for package types.

FlagDefaultDescription
-p, --pathoffShows 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 .git directory exists).
  • The git repository has an origin remote.
  • sfdx-project.json exists.
  • At least one package is defined.

The command exits with code 1 when any check fails.

FlagDefaultDescription
-f, --fixoffPrints 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.

FlagDefaultDescription
-m, --migrateoffMigrates 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>detectednpm 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>pnpmPackage manager for the workspace. Use pnpm. The flag also accepts npm and yarn, which this documentation does not cover.
--workspace-dir <dir>noneDirectory 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, --yesoffSkips prompts and uses defaults.
--jsonoffPrints 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:build

The 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.

FlagDefaultDescription
--api-version <value>sourceApiVersion from sfpm.config.tsOverrides the Salesforce API version for this run, such as 63.0.
--jsonoffPrints 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.

FlagDescription
-M, --majorIncrements the major version.
-m, --minorIncrements the minor version.
--patchIncrements 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.

FlagDescription
-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, --allBumps every package. Same as passing no selector.

Other flags:

FlagDefaultDescription
--dryrunoffPrints the planned changes and writes nothing.
-f, --projectfile <path>sfdx-project.jsonPath 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 main

sfpm 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.

FlagDefaultDescription
-n, --name <name>nonePackage name without the npm scope. Required with --json. Prompted otherwise.
-t, --type <type>unlockedunlocked, source, or data. Prompted otherwise.
-s, --scope <scope>nonenpm 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>noneDevHub for creating the Package2 container of an unlocked package. Without it, interactive runs ask whether to create one, and --json runs create none.
--org-dependentoffCreates an org-dependent unlocked package. Applies to unlocked packages only.
--jsonoffRuns 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 --json

After 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-b

Next steps

Build the packages you created or migrated with the build command. Deploy or install them with the deploy and install commands.

On this page