Project
A Project in Salesforce DX is a local directory that the Salesforce CLI recognizes as a unit of source-driven development.
Definition
A Project in Salesforce DX is a local directory that the Salesforce CLI recognizes as a unit of source-driven development. It holds an sfdx-project.json configuration file, your metadata in source format, scratch org definitions, and the Git history your team works against. The CLI reads the project to know where source lives and how to sync it with an org.
People also call it a DX project or a local project. It is the starting point for building, testing, and deploying customizations without clicking through the Setup UI. You generate one with the command sf project generate, then track the whole folder in version control.
How a Salesforce DX project is put together
The sfdx-project.json file is what defines the project
The presence of sfdx-project.json is what turns an ordinary folder into a Salesforce DX project. The CLI looks for this file at the root, and if it is missing, commands that expect a project will fail. The file is plain JSON, so it sits comfortably in Git and is easy to diff during code review. Inside, the most important attribute is packageDirectories. It is an array of folders that hold your source, and one entry is marked default. The default directory is where the CLI puts metadata when you pull changes from an org without naming a target. A fresh project ships with a single force-app directory set as the default. Other common attributes include sourceApiVersion, which pins the metadata API version used during deploy and retrieve, namespace for packaging, and sfdcLoginUrl to point at a non-standard login host. Teams that build managed or unlocked packages also add package, versionName, and versionNumber entries here so the CLI knows how to cut new package versions.
What the generate command scaffolds
Running sf project generate builds a predictable folder layout so every teammate starts from the same shape. You get the sfdx-project.json file at the root, a force-app directory for your source, a config folder, and a manifest folder. The config folder contains project-scratch-def.json, the definition file that describes the edition, features, and settings of any scratch org you spin up from this project. Checking that file into Git means the whole team creates identical throwaway orgs from one shared spec. The manifest folder holds a starter package.xml, which lists the components you want to deploy or retrieve when you work in the older manifest-driven style. You also get a hidden .forceignore file that tells the CLI which files to skip during sync, similar to how .gitignore works for Git. A .sf or .sfdx directory stores local state and should stay out of source control. The result is a clean, conventional starting point rather than an empty directory you have to organize by hand.
Source format keeps metadata friendly for Git
Metadata inside a project is stored in source format, not the older metadata API format. The difference matters for version control. In metadata API format, large objects arrive as single sprawling XML files, so two people editing different fields on the same object end up fighting over the same file. Source format decomposes those big files into smaller pieces. A custom object, for example, breaks apart so each field, validation rule, and list view lands in its own file under a folder named for the object. Smaller files mean cleaner diffs and far fewer merge conflicts. When a reviewer opens a pull request, they see exactly which field changed instead of scrolling through hundreds of unrelated lines. If you inherit an org built the classic way, the CLI can convert metadata API format into source format with sf project convert mdapi, and convert back with sf project convert source when a deployment target still expects the old shape. Source format is the reason DX projects feel like normal software repositories.
The project is the hub of the develop loop
The project sits in the middle of a tight loop between your laptop and an org. A developer clones the repository, opens the project, and authorizes a scratch org or a sandbox through the CLI. From there the rhythm is push, edit, pull, commit. You push local source into a scratch org with sf project deploy start, make changes either in code or by configuring features in the org UI, then pull those org changes back into the project with sf project retrieve start. Source tracking watches what changed on each side so you rarely move more than you intend. Once a feature is working, you commit the updated files to Git and open a pull request. Because the entire state of the app lives in the project folder, a new teammate can reproduce your work from a clean checkout. This loop replaces the brittle habit of editing directly in a shared sandbox, where changes are invisible until someone notices them.
Multiple package directories for modular orgs
A single default force-app folder is fine for a small app, but large orgs benefit from splitting metadata into several package directories. You create more folders, list each one in packageDirectories, and group related components together. One directory might hold billing logic, another the customer portal, another shared utilities. This grouping is the foundation for unlocked packages, where each directory becomes its own versioned, deployable artifact. The CLI deploys directories in the order they appear in the array, which lets you express dependencies, putting shared code first so dependent modules build on top of it. Modular directories also make ownership clearer. A team can own one folder and review changes to it without wading through the entire org. Even teams that never adopt packaging use multiple directories to keep a sprawling org organized. The key rule is that exactly one directory carries default true, since the CLI needs a single home for retrieved metadata that you did not explicitly route somewhere else.
Where the project fits in CI and CD
Because a project is just files in Git, it plugs straight into continuous integration. A pipeline checks out the repository, installs the Salesforce CLI, authorizes a target org with a stored credential, and runs deploy and test commands against the project. Nothing about that flow depends on a human clicking in Setup. A typical pull request pipeline spins up a fresh scratch org from project-scratch-def.json, deploys the source, runs Apex tests, and tears the org down. That gives reviewers a clean signal that the change deploys and passes tests in isolation. Promotion pipelines then deploy the same source to integration, staging, and production sandboxes or the production org, often using sf project deploy validate first to confirm a deployment will succeed before committing to it. The project is the single source of truth that every environment is built from, which is the whole point of source-driven development. It removes the guesswork of wondering whether an org matches what is in the repository.
How to create a Salesforce DX project
You create a Salesforce DX project from the command line, not from the Setup UI. Install the Salesforce CLI first, then generate the project folder and open it in your editor. These steps produce a tracked, ready-to-develop project.
- Install and verify the CLI
Install the Salesforce CLI, then run sf --version to confirm it resolves. The unified sf CLI replaced the original sfdx executable, so make sure you are on a current build before you start.
- Generate the project
Run sf project generate --name my-app from the folder where you want the project to live. The CLI scaffolds sfdx-project.json, a force-app directory, config, and manifest folders inside a new my-app directory.
- Put it under version control
Change into the new folder and run git init, then commit the generated files. Tracking the project from the first commit means every later change shows up cleanly in history and code review.
- Authorize an org and start the loop
Authorize a Dev Hub or sandbox with sf org login web, then create a scratch org or set a default org. Now you can deploy source into the org, retrieve changes back, and commit your work.
Passed with --name; becomes both the new folder name and the project name recorded in sfdx-project.json.
Generated automatically; its packageDirectories array with one default path is required for the CLI to treat the folder as a project.
The force-app folder created by default; exactly one directory must carry default true so retrieved metadata has a home.
- Running CLI commands that expect a project from outside the project root fails, because the CLI cannot find sfdx-project.json. Run them from the folder that holds that file.
- Keep the .sf or .sfdx state directory out of Git by leaving it in .gitignore. It holds local, machine-specific data that should not be shared.
- Exactly one package directory can be the default. Marking two with default true is a configuration error the CLI will reject.
- The --template flag picks the starting layout. Use the standard template for general work; the empty template skips the sample force-app structure if you want to build it yourself.
Prefer this walkthrough as its own page? How to Project in Salesforce, step by step
Trust & references
Cross-checked against the following references.
- Salesforce DX Project ConfigurationSalesforce
- Project Setup (Salesforce DX Developer Guide)Salesforce
Straight from the source - Salesforce's reference material on Project.
Hands-on resources to go deeper on Project.
About the Author
Dipojjal Chakrabarti is a B2C Solution Architect with 29 Salesforce certifications and over 13 years in the Salesforce ecosystem. He runs salesforcedictionary.com to help admins, developers, architects, and cert/interview candidates sharpen their fundamentals. More about Dipojjal.
Test your knowledge
Q1. In Salesforce DX, what is a Project?
Q2. Which command scaffolds a new Salesforce DX Project directory?
Q3. In the source-driven workflow, what role does Git play for a DX Project?
Discussion
Loading discussion…