Newer Version Available

This content describes an older version of this product. View Latest

Multiple Package Directories

When you create your Salesforce DX project, we recommend that you organize your metadata into logical groupings by creating multiple package directories locally. You then define these directories in your sfdx-project.json file. You can group similar code and source for an application or customization to better organize your team’s repository. Later, if you decide to use second-generation packages (2GP), these directories correspond to the actual 2GP packages.

For clarity in this topic, package directory refers to the local (client-side) directory that contains decomposed metadata files, that is, metadata in source format. This directory doesn’t always result in a 2GP package. Package refers to a 2GP package.

Also, the terms push and deploy are interchangeable; both mean moving metadata components from your local project to your org. Similarly, pull and retrieve are interchangeable. In this topic, we generally use the terms deploy and retrieve. However, we use the terms push and pull when talking about the specific actions of the force:source:push|pull commands.

Note

In your sfdx-project.json file, list each package directory separately in the packageDirectories section. Each local package directory adheres to the standard Salesforce DX project structure.

The multiple package directory structure is client-side (local) only. When you deploy the source to the org with force:source:deploy or force:source:push, there’s no association between its local package directory location and the package in the org. You specify that metadata belongs to a specific 2GP package in an org by explicitly installing the 2GP package.

All of the force:source:* commands support multiple package directories.

Considerations

Before setting up multiple package directories, read these considerations.

  • By default, both force:source:deploy and force:source:push deploy metadata to your org in a single transaction, regardless of the order that you list your multiple package directories in sfdx-project.json. The force:source:push command pushes all changed and new metadata in all package directories; force:source:deploy deploys only the metadata that you specify. If you want to use force:source:push, but also want to specify the order that the package directories are pushed, use the pushPackageDirectoriesSequentially property of sfdx-project.json. See Push Source Sequentially for details.
  • By default, the force:source:deploy|retrieve commands don't track changes in your source files. Enable source tracking for these commands by specifying the --tracksource parameter each time you run the command. The force:source:deploy|retrieve commands then use the same internal source tracking files as the force:source:push|pull commands. Be sure you use this parameter if you use force:source:deploy|retrieve and force:source:push|pull together. If you don't, the internal source-tracking files get out of sync. The force:source:push|pull commands always track your source changes.

How Do I Set It Up?

Setting up multiple package directories is easy. How you organize your local source code among these directories takes more thought and planning, and depends on your development environment. Plan how to organize your code before you get started. Keep your source code well organized as your project grows to make it easier and more efficient for your developers to work.

Let’s look at a simple example. Say you put the decomposed metadata files for a custom object MyObject in the default package directory. You can then put files for a new field MyField on MyObject in a different “extension” package directory without having to also include the MyObject files. There are many ways to organize your code, and describing all the ways is out of scope of this topic. These blog posts provide some ideas.

Here’s how you set up multiple package directories. Let’s first look at a sample sfdx-project.json snippet:

This sfdx-project.json snippet defines three package directories: es-base-custom (the default), es-base-ext, and es-base-styles. Let’s say your top-level local project directory is called easy-spaces-lwc. The directory hierarchy underneath it would look something like this:

Image showing directory hierarchy of the easy-spaces-lwd project directory.

Each es-base-* directory adheres to the standard Salesforce DX project structure. For example, es-base-ext would look something like:

Image showing directory hierarchy of es-base-ext subdirectory of the easy-spaces-lwc project directory.

Now add the decomposed metadata source to these multiple package directories in the way that best suits your development environment.

How Does It Work?

Let's go through a few examples to see how force:source:push|pull and force:source:deploy|retrieve work with multiple package directories.

The examples in this section assume you're using the force:source:deploy|retrieve and force:source:push|pull commands together. To ensure that source-tracking stays in sync, the force:source:deploy|retrieve examples use the --tracksource parameter.

Note

For new orgs, the force:source:push command pushes all the metadata in all multiple package directories listed in your sfdx-project.json file. After that, the command pushes metadata that's new, changed, or marked for delete. By default, the command pushes the metadata in a single transaction, as if you had just one package directory.

In contrast, use force:source:deploy to target the metadata you want to deploy. You can deploy specific package directories, specific metadata components, components listed in a manifest file, and more. This example deploys the metadata in the es-base-custom package directory:

This example deploys all Apex classes found in all your multiple package directories:

When you run force:source:pull, the command pulls all remote changes from the org into your local project. For each retrieved component, the command looks in all package directories for a local match. If it finds a match, the command updates it. If it doesn't find a match, the command copies the local component into the default package directory, which in our example is es-base-custom.

You can then move the pulled files into the package directory that makes sense for your project. After you push the moved files back up to the org with force:source:push, Salesforce CLI tracks their new location.

Use force:source:retrieve to retrieve targeted metadata from your org. Similar to force:source:pull, existing metadata is retrieved into its correct local package directory and new metadata into the default package directory. This example retrieves only the metadata components contained in the local es-base-custom package directory:

This example retrieves all Apex classes from your org; new classes go into the default package directory and classes that exist locally go into their corresponding package directory.

Push Source Sequentially

As we've mentioned, force:source:push, by default, pushes metadata in all package directories in a single transaction without regard to order. Using a single transaction is much faster for most projects. But sometimes you must specify the exact order that the package directories are pushed. Reasons include:
  • The number of recomposed metadata component files in your local project exceeds the Salesforce metadata limit of 10,000 files per retrieve or deploy. One workaround is to split up your metadata into multiple package directories that each contain less than this limit and push each directory sequentially, and thus separately.
  • You have dependencies between multiple package directories, which requires that they be pushed in a specific order.
  • More than one package directory contains the same metadata component, and you want to specify which one is deployed last so it's not overwritten.

To specify that the multiple package directories are pushed in the order they're listed in sdfx-project.json, add "pushPackageDirectoriesSequentially": true to the file. For example:

When you run force:source:push, the command executes three separate pushes in this order: first the metadata from es-base-custom, then es-base-ext, and then es-base-styles.

The pushPackageDirectoriesSequentially property doesn't affect how force:source:deploy works. If you need multiple deployments in a specific order when using the force:source:deploy command, run the command several times using the -p or -m parameters in the order you wish.

Important