Skip to main content
Structuring your source control repository

Gearset supports the Metadata API and SFDX source format directory structure in version control

Oli Lane avatar
Written by Oli Lane
Updated over a year ago

When storing your metadata in source control, there are several options for how to store the metadata and where to put it in your repository. Your metadata needs to be structured correctly so that Gearset can find it.

Metadata API format

This is the standard format for Salesforce metadata, and is what you will be familiar with if you've used Ant, Eclipse or Workbench for deployments before. It's also the structure used by the sfdx force:mdapi:deploy command.

Normally the structure for a Metadata API formatted repository is something like:

<root directory>/
└── unpackaged/
    ├── objects/
        └── SomeObject__c.object
    ├── permissionsets/
    ...
    └── profiles/
        ├── MyProfile.profile
        └── MyOtherProfile.profile

The root directory contains an unpackaged directory, and all the metadata is inside it. Putting the metadata directly inside the root directory is also supported by Gearset:

<root directory>/
├── objects/
    └── SomeObject__c.object
├── permissionsets/
...
└── profiles/
    ├── MyProfile.profile
    └── MyOtherProfile.profile

Gearset also supports putting all the metadata inside a src directory, which is the structure used by Eclipse:

<root directory>/
└── src/
    ├── objects/
        └── SomeObject__c.object
    ├── permissionsets/
    ...
    └── profiles/
        ├── MyProfile.profile
        └── MyOtherProfile.profile

Using a package.xml file

Optionally, when using the Metadata API format, you can include a package.xml file in your repository. This can be used in Gearset to filter your comparisons. However, it must be located correctly, since it is also used by Gearset to locate your metadata folder.

Gearset does not support a branch with multiple package.xml files. Gearset may have problems parsing your branch if multiple package.xml files are present.

If a package.xml file is present anywhere in the repository, Gearset will use the directory that contains it as the root of your metadata. For example, Gearset will be able to find the metadata in this repository, which uses some-other/metadata-directory as the root for its metadata:

<root directory>/
└── some-other/
    └── metadata-directory/
        ├── package.xml
        ├── objects/
            └── SomeObject__c.object
        ├── permissionsets/
        ...
        └── profiles/
            ├── MyProfile.profile
            └── MyOtherProfile.profile

If you have a package.xml folder placed somewhere other than the root of your metadata, then Gearset will not be able to locate your metadata. For example, in the following example Gearset will treat the root of the repository as the metadata directory and will not find any of the metadata:

<root directory>/
├── package.xml      <--- This will stop Gearset from
└── unpackaged/           finding the metadata
    ├── objects/
        └── SomeObject__c.object
    ├── permissionsets/
    ...
    └── profiles/
        ├── MyProfile.profile
        └── MyOtherProfile.profile

In this case the package.xml file should be removed, or moved to the unpackaged folder.

Using the Salesforce DX source format

Salesforce DX has a new format for structuring metadata. It's the same structure used by the sfdx force:source:pull and sfdx force:source:push commands. Gearset supports this structure natively, and will automatically translate as necessary when deploying to and from repositories in the SFDX source format.

In order for Gearset to detect your repository as being in SFDX source format, it looks for a sfdx-project.json file. If this file is not present in the root directory, Gearset will treat the repository as a Metadata API formatted repository, and will not find your metadata.

The following is an example of a correctly formatted SFDX source format repository:

<root directory>/
├── sfdx-project.json
└── force-app/
    └── main/
        └── default/
            └── objects/
                └── Asset/
                    └── Asset.object-meta.xml
                ...
                ...
                ...
                └── profiles/
                    ├── MyProfile.profile-meta.xml
                    └── MyOtherProfile.profile-meta.xml

(Note that this guide replaces the force-app folder name with unpackaged; this is supported as long as the path variable in the sfdx-project.json matches the folder name.)

You can also use our sample SFDX source format repository to copy or fork from to help you see what the structure should look like.

By default, Gearset will write your metadata in the SFDX source format if your repository is empty.

If your repository already has metadata, Gearset will write in the SFDX source format only if it detects a correctly placed sfdx-project.json file. If the repository already has metadata but no sfdx-project.json file, then Gearset will write in the MDAPI format.

Restrictions to which metadata is picked up

Gearset will pick up metadata as long as two rules are met:

  1. The metadata is in a subdirectory listed as a package directory in the sfdx-project.json file.

  2. The metadata file/directory is not excluded by a rule in a .forceignore file.

Therefore, you can use either of these rules to include/exclude metadata from a comparison or deployment by Gearset.

Support for repositories with multiple SFDX package directory paths

Gearset supports multiple paths in the packageDirectories in the sfdx-project.json. We use all the paths to search for metadata to compare.

If default is set to true for a package directory, it will be searched first for metadata, if multiple packages have default set to true they will be prioritized over non default packages for searching. The path can have multiple package levels of any name, we usually use the default force-app, but any valid path is usable.

A listed packageDirectory can not be a sub path of another packageDirectory path. I.e.:
- foo/bar
- foo/baz
are valid, but
- foo/bar
- foo/bar/baz
are not valid, as the paths conflict - it's ambiguous which packageDirectory the baz folder belongs to.

Inside these packageDirectories is where we look for metadata to compare. We look for metadata at any folder depth inside the packageDirectories path. If force-app was our packageDirectories path, these are examples of metadata Gearset will pick up:


- force-app/main/default/applications/Dreamhouse.app-meta.xml

- force-app/classes/MyClass.class-meta.xml

- force-app/one/foo/bar/objects/Account.object-meta.xml

After the packageDirectories path, any folders levels can be named whatever you like, and you can split your metadata up into folders however you like, such as:
- main/default/
- main/test/
- my-feature-1/default/
- foo/bar/my-feature-2/my-component-1/
- my-component-2/

Gearset first looks for a folder of a known metadata type (aura, lwc, applications, classes, pages etc.), and then loads metadata from inside here. It will still try to process the metadata if this is not named something we expect, but it is not ideal.

Inside the final "metadata folder" should be the metadata file, however for simple types which occur as a flat list of files inside this folder, it can be in subsequent folders named anything you like, i.e. both these paths are valid:
foo/bar/applications/Dreamhouse.app-meta.xml
foo/bar/applications/baz/Dreamhouse.app-meta.xml

How does Gearset decide which package directory to deploy metadata to?

Because metadata can be split across multiple package directories, Gearset uses a set of rules to determine where a piece of metadata should be deployed. This is particularly important in the case of metadata that is split into multiple files in SFDX source format repos, e.g. Custom Objects.

For metadata that is stored as a flat list of files (e.g. Apex Classes, Profiles), Gearset uses the following rules:

  1. If this file does not exist in the repo at all, we just deploy to the default project (listed in sfdx-project.json, with subdirectories as follows: <UserDefault>/main/default)

  2. If the file already exists in the repo in a single location, deploy the changes here.

  3. If this file is detected in multiple places in the target repo, Gearset will raise an error as a repo should not contain duplicate metadata, and Gearset can not pick where to deploy to.

For metadata that is split across multiple files, the rules are slightly different. For example, suppose that you are deploying a custom field, Gearset will use the following rules:

  1. If the custom object for this field does not exist in the repo at all, Gearset will deploy to the default package directory (listed in sfdx-project.json, with subdirectories as follows: <UserDefault>/main/default).

  2. If the custom object already exists in the repo in a single location, deploy the field here. (e.g. the case when an object is in a single package directory).

  3. If the custom object is split across multiple package directories, and this field already exists in one, pick this location and update this existing file.

  4. If there are multiple locations with this custom object but the field does not exist in any, pick the location that is inside the packageDirectory listed as "default: true" in sfdx-project.json.

  5. If there are multiple locations with this custom object and none are in the default package directory - we can't pick. Here Gearset reverts to the default location: <UserDefault>/main/default.

  6. If this field is detected in multiple places in the target repo, Gearset will raise an error as a repo should not contain duplicate metadata, and Gearset can not pick where to deploy to.

How does Gearset store CPQ Config data?

The initial commit will create a folder in the repo called configdata/ with a file named gearset-config-data-project.json and a folder for each object type, which will contain a .gs.json file for each record. After the initial commit you can rename/move the folder. Gearset will look for the gearset-config-data-project.json file and use that as the directory to commit new config data files.

These files can live alongside other current metadata files. More FAQ's on Comparing and deploying CPQ configuration with source control

Did this answer your question?