sfpm
Getting started

Quick start

Migrate an existing sfdx project into a workspace, then sync, build, and deploy a package.

This walkthrough turns an existing sfdx project into an sfpm workspace, then builds and deploys one package. You need sfpm installed, and the Salesforce CLI authenticated to a target org. A DevHub is only needed if you build with org or full validation, which step 3 covers. See Installation.

The project must have an sfdx-project.json with at least one named package. If it does not, see Starting without an sfdx project at the end of this page.

Replace @myorg, my-package, my-devhub, and my-sandbox with your own values.

1. Convert the project

From the project root:

sfpm project init turbo --migrate --npm-scope @myorg

The command writes a root package.json, pnpm-workspace.yaml, and turbo.json. It also writes one package.json into each package's existing directory. Your metadata does not move. An interactive run without --yes asks where package directories should live; choose "Keep original paths", not "packages/" or "Custom..." (those produce the broken --workspace-dir layout). Add --yes to skip the prompts and use this safe default automatically.

Migrate an existing project describes each file and the review steps.

2. Install and sync

pnpm install
sfpm project sync

sfpm project sync generates sfdx-project.json from the package.json files. Edit the package.json files, not sfdx-project.json.

3. Build

sfpm build my-package

The default validation level is local. At this level, an unlocked package builds as a source package. No DevHub is used and no package version is created. Nimbus checks run when Nimbus is installed.

To build an unlocked package as a package version, use org validation with your DevHub. The version is created in the DevHub:

sfpm build my-package -v my-devhub --validation org

-v names the DevHub.

A package's packageType is set in its package.json. Migration sets packageType to unlocked for every package, unless its packageDirectories entry has a type key. If a package is a source package, change its packageType to source before you build.

4. Deploy

sfpm deploy my-package -o my-sandbox

sfpm deploy deploys the package from local source to the target org. -o sets the target org.

Starting without an sfdx project

If you have no sfdx-project.json yet, create the workspace by hand. The migration needs an existing project, so this path skips it.

sfpm project init turbo --npm-scope @myorg --yes
mkdir -p packages/core/force-app

Create packages/core/package.json:

{
  "name": "@myorg/core",
  "version": "1.0.0",
  "private": true,
  "sfpm": {
    "packageType": "unlocked",
    "path": "force-app"
  }
}

Org or full validation of an unlocked package creates a package version, which needs a Package2 ID. Create the Package2 in your DevHub with the Salesforce CLI, then set its ID as sfpm.packageId in this file. At the default local validation level, the package builds as a source package without one.

Then run pnpm install, sfpm project sync, the build, and the deploy from the steps above, using core as the package name.

Add each further package the same way: its own directory under packages/, with its own package.json. sfpm package create is not a working shortcut for this today: it always writes the new package at the project root, so a workspace scaffolded this way never discovers it. Create the directory and package.json by hand instead, as shown above.

Every command supports --help. See the CLI reference for the full flag list.

On this page