salesforce-dx-project-structure

Use this skill when setting up, configuring, or troubleshooting sfdx-project.json, organizing packageDirectories for mono-repo or multi-package projects, managing sourceApiVersion alignment, and structuring the force-app directory tree for source-driven development. NOT for scratch org definition files (use scratch-org-management), CLI command usage (use sf-cli-and-sfdx-essentials), or CI/CD pipeline configuration (use github-actions-for-salesforce or bitbucket-pipelines-for-salesforce).

Best use case

salesforce-dx-project-structure is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Use this skill when setting up, configuring, or troubleshooting sfdx-project.json, organizing packageDirectories for mono-repo or multi-package projects, managing sourceApiVersion alignment, and structuring the force-app directory tree for source-driven development. NOT for scratch org definition files (use scratch-org-management), CLI command usage (use sf-cli-and-sfdx-essentials), or CI/CD pipeline configuration (use github-actions-for-salesforce or bitbucket-pipelines-for-salesforce).

Teams using salesforce-dx-project-structure should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/salesforce-dx-project-structure/SKILL.md --create-dirs "https://raw.githubusercontent.com/PranavNagrecha/AwesomeSalesforceSkills/main/skills/devops/salesforce-dx-project-structure/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/salesforce-dx-project-structure/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How salesforce-dx-project-structure Compares

Feature / Agentsalesforce-dx-project-structureStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Use this skill when setting up, configuring, or troubleshooting sfdx-project.json, organizing packageDirectories for mono-repo or multi-package projects, managing sourceApiVersion alignment, and structuring the force-app directory tree for source-driven development. NOT for scratch org definition files (use scratch-org-management), CLI command usage (use sf-cli-and-sfdx-essentials), or CI/CD pipeline configuration (use github-actions-for-salesforce or bitbucket-pipelines-for-salesforce).

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# Salesforce DX Project Structure

This skill activates when you need to create, configure, or troubleshoot the root project configuration file (`sfdx-project.json`) and directory layout for a Salesforce DX project. It covers packageDirectories configuration, sourceApiVersion management, multi-package mono-repo organization, namespace handling, and the standard source-format directory tree.

---

## Before Starting

Gather this context before working on anything in this domain:

- Is this a new project or a restructure of an existing one? If existing, read the current `sfdx-project.json` first.
- How many packages or independent workstreams will share this repository? This determines single vs. multi-package directory layout.
- What API version does the target org support? Deploying with a `sourceApiVersion` higher than the org supports causes `UNSUPPORTED_API_VERSION` failures.

---

## Core Concepts

Understanding DX project structure requires clarity on four areas: the project configuration file, package directories, source format layout, and API version alignment.

### sfdx-project.json

The `sfdx-project.json` file is the root configuration file for every Salesforce DX project. It lives at the repository root and is required for all `sf` CLI operations. The file must contain at minimum a `packageDirectories` array with at least one entry. Other top-level keys include `sourceApiVersion`, `namespace`, `sfdcLoginUrl`, `signupTargetLoginUrl`, and `plugins`.

The CLI resolves the project root by walking up the directory tree until it finds this file. If the file is missing or malformed, every `sf` command fails immediately.

### packageDirectories

The `packageDirectories` array defines which folders contain deployable metadata. Each entry requires a `path` (relative to the project root). Exactly one entry must have `"default": true` — this is where `sf` CLI commands place newly created metadata by default.

For unlocked or managed packages, each entry can also include `package` (the package name), `versionName`, `versionNumber` (format: `MAJOR.MINOR.PATCH.NEXT`), and `dependencies` (array of package references with minimum version constraints).

### Source Format Directory Layout

Inside each package directory, metadata follows the Salesforce source format tree. The standard structure is:

```
force-app/
  main/
    default/
      classes/
      triggers/
      lwc/
      aura/
      objects/
        Account/
          fields/
          listViews/
      flows/
      permissionsets/
      profiles/
      layouts/
      tabs/
      applications/
      staticresources/
```

Each metadata type has a defined folder name and file extension. Objects decompose into subfolders for fields, list views, record types, and other child components. This decomposed structure enables granular source tracking and conflict-free merging.

### sourceApiVersion

The `sourceApiVersion` is a string (e.g., `"62.0"`) that tells the CLI which metadata API version to use for deploys and retrieves. If this version is higher than the org's API version, the deployment fails with `UNSUPPORTED_API_VERSION`. If it is too low, newer metadata types are silently excluded from retrieves. Best practice: set it to the current API version of your lowest-supported org.

---

## Common Patterns

### Single-Package Project

**When to use:** Small to medium projects with one team deploying from one directory.

**How it works:**

```json
{
  "packageDirectories": [
    {
      "path": "force-app",
      "default": true
    }
  ],
  "namespace": "",
  "sourceApiVersion": "62.0",
  "sfdcLoginUrl": "https://login.salesforce.com"
}
```

All metadata lives under `force-app/main/default/`. The `sf` CLI generates new components here automatically. This is the simplest and most common layout.

**Why not multi-package:** Adding unnecessary package boundaries creates build complexity, dependency management overhead, and longer CI times with no benefit for a single-team project.

### Multi-Package Mono-Repo

**When to use:** Large projects where multiple teams own separate packages, or where you need independent package versioning and deployment ordering.

**How it works:**

```json
{
  "packageDirectories": [
    {
      "path": "packages/core",
      "default": true,
      "package": "CoreDataModel",
      "versionName": "Spring 25",
      "versionNumber": "1.3.0.NEXT"
    },
    {
      "path": "packages/sales",
      "package": "SalesAutomation",
      "versionName": "Spring 25",
      "versionNumber": "2.1.0.NEXT",
      "dependencies": [
        {
          "package": "CoreDataModel",
          "versionNumber": "1.3.0.LATEST"
        }
      ]
    },
    {
      "path": "packages/service",
      "package": "ServiceExtensions",
      "versionName": "Spring 25",
      "versionNumber": "1.0.0.NEXT",
      "dependencies": [
        {
          "package": "CoreDataModel",
          "versionNumber": "1.3.0.LATEST"
        }
      ]
    }
  ],
  "namespace": "",
  "sourceApiVersion": "62.0"
}
```

Each team owns its directory. Dependencies flow upward (sales and service depend on core). Package version creation builds in dependency order automatically.

**Why not a single directory:** With multiple teams, a flat directory causes merge conflicts, unclear ownership boundaries, and makes independent deployment impossible.

### Unpackaged Metadata Alongside Packages

**When to use:** When you have packaged components but also need org-specific configuration (profiles, permission sets, page layouts) that should not be packaged.

**How it works:**

```json
{
  "packageDirectories": [
    {
      "path": "packages/core",
      "default": true,
      "package": "CorePackage",
      "versionName": "v1",
      "versionNumber": "1.0.0.NEXT"
    },
    {
      "path": "unpackaged",
      "default": false
    }
  ],
  "namespace": "",
  "sourceApiVersion": "62.0"
}
```

The `unpackaged/` directory holds metadata that deploys via `sf project deploy` but is never included in package version builds. This is the correct place for profiles, org-specific permission sets, and post-install configuration.

---

## Decision Guidance

| Situation | Recommended Approach | Reason |
|---|---|---|
| Single team, no package versioning needed | Single `force-app` directory, no `package` key | Simplest setup; avoids package build overhead |
| Multiple teams sharing one repo | Multi-package with explicit `dependencies` | Clear ownership; independent versioning; dependency-ordered builds |
| Managed package development | Single package dir with `namespace` set at project level | Namespace applies to all metadata in the project |
| Mix of packaged and org-specific metadata | Separate `unpackaged/` directory entry without `package` key | Keeps org config out of package versions |
| API version mismatch errors on deploy | Lower `sourceApiVersion` to match oldest target org | Prevents `UNSUPPORTED_API_VERSION` rejections |
| Need to support ISV with managed + extension packages | Multi-package with namespace on managed, blank on extensions | Each package can have its own lifecycle |

---

## Recommended Workflow

Step-by-step instructions for setting up or restructuring a Salesforce DX project:

1. **Check for existing configuration** — Look for `sfdx-project.json` at the repo root. If it exists, read it and identify what needs to change. If it does not exist, run `sf project generate --name <project-name>` to scaffold.
2. **Determine package strategy** — Decide whether the project needs a single package directory, multiple packages, or a mix of packaged and unpackaged metadata. Base this on team count, deployment independence requirements, and ISV packaging needs.
3. **Configure packageDirectories** — Add entries for each directory. Ensure exactly one has `"default": true`. For package development, add `package`, `versionName`, and `versionNumber` fields. Wire `dependencies` between packages in the correct order (base packages have no dependencies; downstream packages reference upstream versions).
4. **Set sourceApiVersion** — Set to the current API version of your lowest-supported production org. Verify by running `sf org display --target-org <alias>` and checking the API version in the output.
5. **Create the directory tree** — Build out the source-format folder structure inside each package directory. Follow the standard layout: `<path>/main/default/<metadataType>/`. Run `sf project retrieve start` to pull existing metadata into the correct structure.
6. **Validate the configuration** — Run `sf project deploy start --dry-run --target-org <alias>` to verify the project structure deploys cleanly. Check for path resolution errors, missing metadata types, and API version mismatches.
7. **Commit and verify** — Ensure `sfdx-project.json` is committed. Never commit `sfdxAuthUrl` values, `.sfdx/` local state, or sandbox credentials. Add `.sfdx/`, `.sf/`, and auth files to `.gitignore`.

---

## Review Checklist

Run through these before marking work in this area complete:

- [ ] `sfdx-project.json` exists at the repository root and is valid JSON
- [ ] `packageDirectories` array has at least one entry with a valid `path`
- [ ] Exactly one packageDirectory has `"default": true`
- [ ] `sourceApiVersion` is set and matches or is lower than the target org's API version
- [ ] All `path` values in packageDirectories point to directories that exist
- [ ] Package dependencies reference correct package names and valid version numbers
- [ ] `versionNumber` uses the format `MAJOR.MINOR.PATCH.NEXT` (not `MAJOR.MINOR.PATCH.BUILD`)
- [ ] `.gitignore` excludes `.sfdx/`, `.sf/`, and any auth credential files
- [ ] No `sfdxAuthUrl` or credential values are stored in `sfdx-project.json`

---

## Salesforce-Specific Gotchas

Non-obvious platform behaviors that cause real production problems:

1. **UNSUPPORTED_API_VERSION on deploy** — If `sourceApiVersion` in `sfdx-project.json` is higher than the target org's current API version, the deploy is rejected outright. This commonly happens when a developer updates the version after a Salesforce release but the target sandbox has not been refreshed to the new release yet.
2. **Missing default packageDirectory** — If no entry has `"default": true`, the CLI cannot resolve where to place newly generated metadata. Commands like `sf apex generate class` fail with a cryptic path resolution error rather than a clear "no default directory" message.
3. **Path case sensitivity across OS** — macOS is case-insensitive by default but Linux CI runners are case-sensitive. A `path` of `Force-App` works locally but breaks in CI if the actual directory is `force-app`. This causes intermittent "package directory not found" failures that only appear in pipelines.
4. **Namespace is project-wide, not per-directory** — The `namespace` key applies to the entire project. You cannot assign different namespaces to different packageDirectories within the same `sfdx-project.json`. Multi-namespace development requires separate repositories.
5. **Duplicate path entries silently ignored** — If two packageDirectories point to the same `path`, the CLI uses the first entry and silently ignores the second. This can mask configuration errors where a developer intended separate packages but used the same path.

---

## Output Artifacts

| Artifact | Description |
|---|---|
| `sfdx-project.json` | Root project configuration file with packageDirectories, sourceApiVersion, and optional package metadata |
| Directory layout | Source-format folder tree under each package directory path |
| `.gitignore` additions | Entries for `.sfdx/`, `.sf/`, and auth files to prevent credential leaks |

---

## Related Skills

- `sf-cli-and-sfdx-essentials` — For CLI command usage, authentication, and first-time project setup
- `scratch-org-management` — For scratch org definition files and Dev Hub configuration
- `unlocked-package-development` — For package version creation, installation, and promotion workflows
- `github-actions-for-salesforce` — For CI/CD pipeline configuration that deploys from a DX project
- `environment-strategy` — For org strategy decisions that influence project structure

Related Skills

salesforce-shield-deployment

8
from PranavNagrecha/AwesomeSalesforceSkills

Roll out Shield (Platform Encryption + Event Monitoring + Field Audit Trail) end-to-end, sequencing feature enablement to avoid data lockout. NOT for Classic Encryption or general PE design.

ferpa-compliance-in-salesforce

8
from PranavNagrecha/AwesomeSalesforceSkills

Use this skill when implementing FERPA (Family Educational Rights and Privacy Act) compliance controls in Salesforce Education Cloud or Education Data Architecture (EDA): LearnerProfile FERPA boolean fields, directory information opt-out via FLS and Individual data privacy flags, ContactPointTypeConsent for parental and third-party disclosure, 45-day student records response window tracking, and consent workflow automation. Trigger keywords: FERPA, student records privacy, LearnerProfile, parental disclosure, directory information opt-out, education data privacy, student consent, education cloud compliance. NOT for GDPR/CCPA general data privacy (see gdpr-data-privacy skill), platform encryption at rest (see platform-encryption skill), or HIPAA health-data compliance.

industries-cpq-vs-salesforce-cpq

8
from PranavNagrecha/AwesomeSalesforceSkills

Use this skill when comparing Industries CPQ (formerly Vlocity CPQ) with Salesforce CPQ (Revenue Cloud managed package) — covering feature parity, decision criteria, migration paths, and coexistence patterns. Trigger keywords: Vlocity CPQ, Industries CPQ, Salesforce CPQ comparison, Revenue Cloud migration, CPQ selection, which CPQ to use. NOT for implementing, configuring, or debugging either CPQ product.

tableau-salesforce-connector

8
from PranavNagrecha/AwesomeSalesforceSkills

Tableau ↔ Salesforce integration patterns: Tableau Salesforce connector, Tableau for Salesforce, CRM Analytics alternative, Data Cloud + Tableau, embedded Tableau dashboards. Choose between connector modes (live, extract, direct-to-Data-Cloud). NOT for CRM Analytics Studio (use crm-analytics-foundation). NOT for generic Tableau Server setup.

slack-salesforce-integration-setup

8
from PranavNagrecha/AwesomeSalesforceSkills

Use this skill when setting up or troubleshooting the Salesforce for Slack managed app — including connecting a Salesforce org to a Slack workspace, configuring the three-party admin handshake, linking Slack channels to Salesforce records, enabling record preview sharing, and managing org-level limits. Triggers on: Salesforce for Slack app not connecting, Slack org connection setup, Salesforce record sharing in Slack, Slack workspace admin approval, connecting Salesforce to Slack. NOT for building custom Slack apps or Slack bots (separate development platform), not for Slack Workflow Builder Salesforce connector (use slack-workflow-builder skill), not for Flow-based Slack messaging (use flow-for-slack skill).

salesforce-to-salesforce-integration

8
from PranavNagrecha/AwesomeSalesforceSkills

Use this skill to implement Salesforce-to-Salesforce integration patterns — covering the native S2S feature, API-based cross-org sync, Platform Event bridging, and Salesforce Connect Cross-Org adapter. Trigger keywords: Salesforce to Salesforce integration, cross-org data sharing, S2S feature, cross-org Platform Events, Salesforce Connect cross-org. NOT for multi-org strategy or architecture decisions (use architect/multi-org-strategy), single-org data sharing, or external (non-Salesforce) system integration.

salesforce-maps-setup

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when configuring Salesforce Maps (formerly MapAnything) — territory planning, route optimization, live tracking, geo-grid visualizations, and check-in/check-out workflows for Sales or Service field reps not on Field Service. Covers package installation order (Maps + Maps Advanced + Maps Routing/Live Tracking add-ons), the MapsTerritoryPlan / MapsAdvancedRoute / MapsLayer object family, base-data syncs (Geocoding and Routing services), and integration with Sales and Service Cloud records. Triggers: 'Salesforce Maps setup', 'MapAnything migration', 'territory planning by polygon', 'route optimization for sales reps', 'live tracking field reps', 'plot accounts on a map', 'check-in to the closest account'. NOT for Field Service Lightning territory and scheduling (use admin/fsl-scheduling-optimization-design and data/fsl-territory-data-setup) — Maps and FSL are different products. NOT for Consumer Goods Cloud retail visit planning (use admin/consumer-goods-cloud-setup) — RoutePlan/Visit objects are CG-specific. NOT for Tableau / CRM Analytics geo charts.

salesforce-functions-replacement

8
from PranavNagrecha/AwesomeSalesforceSkills

Salesforce Functions is retired (EOL Jan 2025). This skill maps Functions workloads to replacements: Heroku (with Hyperforce), external containers, Apex (where viable), Agentforce Actions, external compute via Named Credentials. NOT for Lambda / Azure Functions tutorials. NOT for Apex @future replacement (use async-selection tree).

salesforce-data-pipeline-etl

8
from PranavNagrecha/AwesomeSalesforceSkills

Export large Salesforce datasets to a lakehouse via Bulk API 2.0, CDC streams, or Salesforce Data Pipelines. NOT for ad-hoc exports.

salesforce-connect-external-objects

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when deciding whether Salesforce Connect and External Objects are the right fit for external data access, or when reviewing OData, cross-org, and custom adapter patterns, query limitations, and latency tradeoffs. Triggers: 'Salesforce Connect', 'External Objects', '__x', 'OData adapter', 'custom adapter'. NOT for ordinary ETL or replicated-data designs where the data should live inside Salesforce.

outbound-webhook-from-salesforce

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when Salesforce must POST a webhook to a third-party endpoint after a record change — with signed payloads, retries, dead-lettering, rate limits, and idempotency. Covers design choice between Outbound Message, Flow HTTP Callout, Apex Queueable callout, and Event Relay. Does NOT cover inbound webhooks into Salesforce (see inbound-webhook or apex-rest-webhook).

mulesoft-salesforce-connector

8
from PranavNagrecha/AwesomeSalesforceSkills

Designing and configuring MuleSoft Anypoint Salesforce Connector flows: API selection (SOAP/REST/Bulk/Streaming), OAuth 2.0 JWT Bearer auth, watermark-based incremental sync with Object Store, batch processing with record-level error isolation, and replay topic subscriptions. Use when building Mule 4 flows that read from or write to Salesforce, migrating from Mule 3 watermark to Mule 4 Object Store, or troubleshooting connector authentication and API limits. NOT for native Salesforce-to-Salesforce integration without MuleSoft (use platform-events-integration or change-data-capture-integration). NOT for generic REST callout patterns from Apex (use rest-api-patterns).