# Modular YAML configuration

:::important[Enterprise only]

Modular YAML configuration is only available for Workspaces with Enterprise plans. You also need to [store your configuration files in your own repository](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml#storing-the-bitriseyml-file-in-your-repository), not on bitrise.io.

If you are not on an Enterprise plan but interested in modular YAML, [contact us](http://www.bitrise.io/contact)!

:::

Modular YAML configuration enables you to break down large, complex YAML files into smaller, modular components. It allows easier reuse across multiple repositories. By modularizing YAML files, you can quickly locate and update configurations, reducing the risk of errors and merge conflicts.

A modular YAML configuration includes:

- A `bitrise.yml` file in the root of your repository.
- Other YAML files in the same or a different repository. To include a file from a different repository, the repository must belong to the same Git account or organization as the primary repository.
- One or more `include` keywords in the `bitrise.yml` file. These point to other YAML files and bring their configuration into the main project configuration.

After an additional YAML file has been included in the `bitrise.yml` file, you can refer to any of its Workflows or Pipelines as to any other Workflow or Pipeline in your configuration.

## Including configuration from multiple YAML files

To create a modular configuration, you need to:

1. Store your `bitrise.yml` file in your repository.
1. Create more YAML files in addition to `bitrise.yml` and commit them to your repository. We refer to these files as configuration modules.

:::important[File limit]

You can have a total of 50 configuration files, including the root level `bitrise.yml` file.

:::

In `bitrise.yml`, you can include the YAML configuration modules with the `include` keyword. If the module is in the same repository as the `bitrise.yml` file, the `include` keyword requires one parameter: `path` which points to the location of the module.

The provided path must be relative to the repository's root:

```yaml
include:
  - path: file/path/common.yml
```

You can include a YAML configuration module from a different repository by specifying the repository that contains the file. In addition to the `repository` property, you need to also set at least one of the following:

- `branch`: The branch containing the YAML configuration module.
- `commit`: The specific commit hash from which to include the YAML configuration module.
- `tag`: The Git tag that points to the YAML configuration module.

The repository must belong to the same Git account or organization that your project's primary repository belongs to. You can check your [Bitrise project's repository URL](/bitrise-platform/projects/configuring-the-repository-url-and-the-default-branch#changing-the-repository-url) on bitrise.io. For example, if your repository URL is git@github.com:MyOrg/main_repo.git, you can only refer to repositories belonging to MyOrg on GitHub.

You only need to refer to the repository's name. For example, you can refer to git@github.com:MyOrg/another_repo.git with the value `another_repo`.

```yaml
include:
  - path: shared/common.yml
    branch: test_branch
    repository: another_repo
```

:::important[Accessing other repositories]

Bitrise needs `read` access to all repositories where configuration YAML files are hosted. There are two ways to make sure Bitrise can access your repo:

- If you use the [GitHub App](/bitrise-platform/repository-access/github-app-integration) integration, you can [link additional repositories](/bitrise-platform/repository-access/github-app-integration#additional-linked-repositories-via-a-github-app) to your project.
- For other authentication methods, check out this guide: [Apps with submodules or private repo dependencies](/bitrise-platform/repository-access/apps-with-submodules-or-private-repo-dependencies)

:::

## The `include` format

| Parameter | Required? | Description |
| --- | --- | --- |
| `path` | Required | The location of the YAML file you want to include. The path is relative to either:  - The root of the repository in a CI environment. - The current directory in a local environment. |
| `branch` | Optional | The branch from which to include the YAML file. |
| `tag` | Optional | The tag from which to include the YAML file. If `branch` and `tag` are both specified, tag takes priority. |
| `commit` | Optional | The specific commit hash from which to include the YAML file.  If `branch`, `tag`, and `commit` are all specified, the commit takes priority. |
| `repository` | Optional | The repository from which to pull the YAML file. You just need to set the name of the repository, not the URL. |

## Defining configuration modules

A configuration module is a full YAML configuration file. That means that all configuration elements of a valid `bitrise.yml` file are available: you can define the `format_version`, app level Environment Variables, default stacks and machine types, and of course Pipelines, Stages, and Workflows in a configuration module.

For example, you can create a bare minimum `bitrise.yml` file that simply points to another module:

```yaml
include:
  - path: path/to/config_module.yml
```

And in this case, `config_module.yml` contains the entire configuration for the build:

```yaml
format_version: 13
default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git
project_type: android
app:
  envs:
  - MY_NAME: My Name
workflows:
  test:
    steps:
    - script:
        inputs:
        - content: echo "Hello ${MY_NAME}!"
```

A configuration module can contain any configuration entity defined on the root level. For example, a configuration module defining only a single Workflow or just app-level Environment Variables is perfectly valid.

The `bitrise.yml` file:

```yaml
format_version: 13
default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git
include:
  - path: path/to/config_module.yml
```

The `config_module.yml` file:

```yaml
app:
  envs:
  - USER_NAME: UserName
workflows:
  test:
    steps:
    - script:
        inputs:
        - content: echo "Hello ${USERNAME}!"
```

However, non-root level entities cannot stand alone in a separate module file either: you can't, for example, include Step inputs like this.

### Nesting included modules

You can use the `include` property in included configuration files:

Root level `bitrise.yml` file:

```yaml
format_version: 13
default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git
include:
  - path: path/to/config_module.yml
```

The `config_module.yml` file:

```yaml
include:
  - path: path/to/another_module.yml
```

The `another_module.yml` file:

```yaml
workflows:
  ui_test:
    steps:
    - pull-intermediate-files@1:
        inputs:
        - artifact_sources: build_tests.build_for_ui_testing
```

With this configuration, you'll be able to run the `ui_test` Workflow.

Nesting has the following limitations:

- A depth of 10, including the root level file.
- Maximum 50 configuration files in total, including the root level file.

### Merge rules for included modules

When Bitrise runs a build, we merge your configuration modules into a single `bitrise.yml` file:

- Included modules are read and merged into the configuration in the order defined in the root `bitrise.yml` file.
- If an included module also uses include, the nested module is merged first recursively.
- After all configuration files added with include are merged together, the resulting configuration is merged with the `bitrise.yml` file on the root level. As such, you can override configuration values on the root level.

:::note[Switching back to bitrise.io]

If you have a modular configuration with multiple YAML files and you [switch back to storing your configuration on bitrise.io](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml#moving-the-bitriseyml-file-back-to-bitriseio), we use the same merge rules to merge all your files into a single `bitrise.yml` file.

:::

When merging the configurations, it is possible to encounter overlaps and override included configuration values. When merging YAML modules, the most recently read file takes priority over the existing merged configuration. Here are the rules:

- Items of simple types (such as integers and booleans): The value from the most recently read file is used.
- Items of object type (for example, Pipelines, Stages, Workflows):

  - If a property is only present in the existing merged configuration, that value is retained.
  - If a property is present in both, and their values are hash maps, the values are merged.
  - In any other case, the value from the most recently read file is used.
- Items of array type (for example, lists of Environment Variables or [trigger map items](/bitrise-ci/run-and-analyze-builds/build-triggers/yaml-syntax-for-build-triggers)): if the collection is present in both the most recently read file and the existing merged configuration, the merged value is an ordered array of values, with all values from the merged configuration followed by the values from the most recently read file.

You can see the merged configuration in the Workflow Editor on the **Merged config** tab. For how to open and edit the individual modules from there, see [Editing a modular configuration in the Workflow Editor](/bitrise-ci/configure-builds/configuration-yaml/editing-a-modular-configuration-in-the-workflow-editor).

To see the merged result on your computer, run [`bitrise yml merge`](/bitrise-ci/bitrise-cli/working-with-bitrise-yml-via-the-bitrise-cli#merging-a-modular-configuration). This command needs Bitrise CLI 3.0.0 or newer.

**Merging rules**

We have the root `bitrise.yml` file which includes a `config_module.yml` file.

The `bitrise.yml`:

```yaml
format_version: 13
default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git
project_type: android

include: 
  - path: path/to/config_module.yml

app:
  envs:
  - USER_ID: UserId
  - PASSWORD: SecurePassphrase
```

The `config_module.yml`:

```yaml
format_version: 10

app:
  envs:
  - USERNAME: UserName

workflows:
  test:
    steps:
    - script:
        inputs:
        - content: echo "Hello ${USERNAME}!"
```

During the merge, the `config_module.yml` and is merged into the configuration. Then the root level `bitrise.yml` is read and then merged. The final configuration looks like this:

```yaml
format_version: 13
default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git
project_type: android

app:
  envs:
  - USER_ID: UserId
  - PASSWORD: SecurePassphrase
  - USERNAME: UserName

workflows:
  test:
    steps:
    - script:
        inputs:
        - content: echo "Hello ${USERNAME}!"
```

- The root level `format_version` property is present in both files. The root level `bitrise.yml` file is merged into the overall configuration last, therefore its value of `format_version` is used.
- The `apps` property is present in both files so all key-value pairs are added to the overall configuration.
- The `test` Workflow is only present in `config_module.yml` so it's added to the overall configuration and `bitrise.yml` does not override it.
