> For the complete documentation index, see [llms.txt](https://docs.flxbl.io/flxbl/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.flxbl.io/flxbl/sfp/development/development-workflow.md).

# 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](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_setup_add_free_license_users.htm), then authenticate:

```bash
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.

```bash
# 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:

```bash
sfp sandbox create -v mydevhub -n my-feature-sandbox -s SourceSandbox
```

`-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

```bash
# Open the org
sfp org open --targetusername my-feature-org
sfp org open --targetusername my-feature-org --browser chrome

# Set a default org for subsequent commands
sfp config set target-org my-feature-org
sfp config set target-org my-feature-org --global
```

## 2. Develop

### Pull the latest metadata

```bash
# Pull using source tracking
sfp pull --targetusername my-feature-org

# Pull a specific package
sfp pull --targetusername my-feature-org --package my-package

# Pull and ignore conflicts
sfp pull --targetusername my-feature-org --ignore-conflicts
```

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](/flxbl/sfp/development/pull-changes-from-your-org.md).

### Add packages

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

```bash
sfp package create source -n feature-payment -r src/payment-processing --repository myorg/myrepo
sfp package create data -n reference-data -r data/reference-data --repository myorg/myrepo
```

See [Creating a package](/flxbl/sfp/development/creating-a-package.md) for the flags each package type accepts.

### Push changes to the org

```bash
# Push using source tracking
sfp push --targetusername my-feature-org

# Push a specific package
sfp push --targetusername my-feature-org --package my-package

# Push everything, ignoring conflicts
sfp push --targetusername my-feature-org --ignore-conflicts
```

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](/flxbl/sfp/development/push-changes-to-your-org.md).

## 3. Run tests

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

```bash
# Test one package
sfp apextests trigger -o my-feature-org -l RunAllTestsInPackage -n sales-core

# Test several packages
sfp apextests trigger -o my-feature-org -l RunAllTestsInPackage -n sales-core -n sales-ui

# Test every package in a domain
sfp apextests trigger -o my-feature-org -l RunAllTestsInDomain -r config/release-config-sales.yaml

# Run named tests during development
sfp apextests trigger -o my-feature-org -l RunSpecifiedTests --specifiedtests PaymentProcessorTest

# Validate per-class coverage
sfp apextests trigger -o my-feature-org -l RunAllTestsInPackage -n sales-core -c -p 80
```

The coverage flags `-c` and `--validatepackagecoverage` are accepted only with `RunAllTestsInPackage`. See [Running Apex Tests](/flxbl/sfp/development/running-apex-tests.md) 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:

```bash
# Build every package
sfp build -v mydevhub

# Build a domain
sfp build -v mydevhub --domain sales

# Build named packages only
sfp build -v mydevhub -p payment-processing

# Build against a branch, with a build number, skipping unchanged packages
sfp build -v mydevhub --branch feature/payment --buildnumber 123 --diffcheck
```

`-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

```bash
# Show a package's direct and transitive dependencies
sfp org dependency explain --package payment-processing

# Make every transitive dependency explicit in sfdx-project.json
sfp org dependency expand -v mydevhub

# Remove redundant transitive dependencies
sfp org dependency shrink -v mydevhub
```

`expand` and `shrink` require a DevHub; `explain` does not. See [Dependency Management](/flxbl/sfp/development/dependency-management.md).

## 6. Submit the change

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

```bash
sfp validate org --repository myorg/myrepo --targetorg validation-org --domain sales --mode thorough --coveragepercent 75
```

`--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](/flxbl/sfp/validating-a-change/overview.md).

## 7. After merge

The pipeline builds the merged change and publishes the artifacts:

```bash
sfp build -v mydevhub --branch main
sfp publish -d artifacts --npm --scope myorg --npmrcpath .npmrc
```

`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](/flxbl/sfp/development/string-replacements.md).

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](/flxbl/sfp/building-artifacts/configuring-installation-behaviour-of-a-package/aliasfy-packages.md).

### Deleting metadata

Deletions are declared as destructive changes in the package rather than by removing files alone. See [Destructive Changes](/flxbl/sfp/concepts/destructive-changes.md).

## Troubleshooting

### Push or pull reports conflicts

```bash
sfp pull --targetusername my-feature-org --ignore-conflicts
sfp push --targetusername my-feature-org --ignore-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:

```bash
sfp server pool replenish --repository myorg/myrepo --tag dev-pool
```

{% hint style="info" %}
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.
{% endhint %}

### Build failures

```bash
sfp build -v mydevhub -p problematic-package --loglevel DEBUG
sfp org dependency explain --package problematic-package
```

### DevHub connection

```bash
sf org login web --alias mydevhub --set-default-dev-hub
sf org display --target-dev-hub
sf limits api display --target-org mydevhub
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.flxbl.io/flxbl/sfp/development/development-workflow.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
