For the complete documentation index, see llms.txt. This page is also available as Markdown.

Development Workflow

This guide walks through the development workflow in a project that uses sfp: fetching an environment, synchronising source with it, testing, and submitting the change.

Prerequisites

An sfp server connection

sfp runs against an sfp server. Commands that reach the server — the sfp pool commands and sfp package create — take a --repository flag identifying the repository they act for, in the form owner/repo for GitHub and GitLab, or org/project/repo for Azure DevOps. The flag defaults to the GITHUB_REPOSITORY or GITLAB_REPOSITORY environment variable, so it can be omitted in a pipeline but must be supplied when you run these commands locally.

The server URL comes from your sfp configuration or from SFP_SERVER_URL.

DevHub access

A DevHub is required for building packages, creating scratch orgs, and creating sandboxes. sfp build takes the DevHub as a required -v flag, so a build fails without one.

Add your user to the DevHub org following Salesforce's guide, then authenticate:

sf org login web --alias mydevhub --set-default-dev-hub
sf org display --target-dev-hub

1. Get a development environment

Environments are fetched from server-managed pools. The same commands serve scratch org and sandbox pools; which one a tag maps to is set in the pool configuration on the server.

# List what is available in a pool
sfp pool list --repository myorg/myrepo --tag dev-pool

# Fetch an org and give it a local alias
sfp pool fetch --repository myorg/myrepo --tag dev-pool --alias my-feature-org

# Fetch and set it as the default org
sfp pool fetch --repository myorg/myrepo --tag dev-pool --alias my-feature-org --set-default

# Extend the assignment before it expires
sfp pool extend --repository myorg/myrepo --tag dev-pool --assignment-id <assignment-id> --extension-hours 24

# Return the org to the pool
sfp pool unassign --repository myorg/myrepo --tag dev-pool

--repository and --tag are required on all four commands; sfp pool extend also requires --assignment-id.

Scratch orgs are typically fetched per story and sandboxes at the start of an iteration, but that is a team convention rather than a constraint of the commands.

Creating a sandbox directly

Where a pool is not in use, a sandbox can be created against the DevHub:

-n names the sandbox and -s names the sandbox to copy from. Passing a definition file with -f is mutually exclusive with -n.

Working with the org

2. Develop

Pull the latest metadata

Without --package, --domain or --source-path, pull uses source tracking and retrieves only what changed in the org. With any of those three, it retrieves everything within that scope. Pull also converts environment-specific values back to placeholders where the package configures replacements. See Pull Changes from your org.

Add packages

A package is a directory plus an entry in sfdx-project.json. sfp package create adds both:

See Creating a package for the flags each package type accepts.

Push changes to the org

Push applies the package's configured replacements before deploying. --ignore-conflicts cannot be combined with --package, --domain or --source-path. See Push Changes to your org.

3. Run tests

sfp executes Apex tests per package rather than across the whole org:

The coverage flags -c and --validatepackagecoverage are accepted only with RunAllTestsInPackage. See Running Apex Tests for test levels, coverage rules, and output formats.

4. Build locally

Building locally confirms the packages resolve and produce artifacts before the pipeline does it:

-v is required. --domain is an alias of --releaseconfig and takes the release config name. -p (--buildOnly) restricts the build to named packages. Artifacts are written to artifacts unless --artifactdir says otherwise.

5. Inspect dependencies

expand and shrink require a DevHub; explain does not. See Dependency Management.

6. Submit the change

Commit and raise a pull request as normal. The pipeline then validates the change:

--repository, --sfp-server-url, --targetorg and --domain (an alias of --releaseconfig) are required; the first two default from environment variables in a pipeline. --mode accepts individual or thorough and defaults to thorough. See Validating a change.

7. After merge

The pipeline builds the merged change and publishes the artifacts:

sfp publish has no registry-URL flag — the registry is read from the .npmrc passed with --npmrcpath.

Common tasks

Environment-specific values

Values that differ per environment are handled with replacements configured in the package's preDeploy/replacements.yml, applied on push and reversed on pull. See String Replacements.

Structural differences — whole files that differ per environment — are handled by aliasified packages instead. When you pull or push a package that sets aliasfy, sfp resolves the directory matching the target org's alias. See Aliasfy packages.

Deleting metadata

Deletions are declared as destructive changes in the package rather than by removing files alone. See Destructive Changes.

Troubleshooting

Push or pull reports conflicts

On push, --ignore-conflicts applies to the whole org and cannot be scoped to a package.

An empty pool

sfp pool list shows what a pool holds. Replenishment is a server operation:

Pool size and replenishment are set in the pool configuration on the server (sfp server pool config update). If a pool is consistently empty, raise it with whoever administers the server rather than replenishing by hand.

Build failures

DevHub connection

Last updated

Was this helpful?