Skip to content

Merge Strategies

Control how arrays and text lines merge when combining base content with per-repo overlays.

Strategies

Strategy Behavior
replace Overlay completely replaces base
append Overlay items added after base items
prepend Overlay items added before base items

File-Level Strategy

Set a default strategy for a file using mergeStrategy:

files:
  .eslintrc.json:
    mergeStrategy: append # extends arrays will append
    content:
      extends: ["@company/base"]

repos:
  - git: git@github.com:org/frontend.git
    files:
      .eslintrc.json:
        content:
          extends: ["plugin:react/recommended"]

Result: ["@company/base", "plugin:react/recommended"]

File-Level vs Inline Control

  • File-level mergeStrategy: Sets the default for ALL arrays in that file
  • Inline $arrayMerge: Overrides the strategy for specific arrays within content

Use file-level when all arrays in a file should merge the same way. Use inline $arrayMerge when you need per-array control, especially in per-repo overlays.

Inline Array Merge Directive

For per-field control, use $arrayMerge and $values directives on individual array fields:

files:
  config.json:
    content:
      features: ["core", "monitoring"]

repos:
  - git: git@github.com:org/repo.git
    files:
      config.json:
        content:
          features:
            $arrayMerge: append
            $values: ["custom-feature"]

Result: ["core", "monitoring", "custom-feature"]

Per-Array Control

Each array field gets its own directive, so sibling arrays can use different strategies:

files:
  config.json:
    content:
      features: ["core", "monitoring"]
      tags: ["production"]

repos:
  - git: git@github.com:org/repo.git
    files:
      config.json:
        content:
          features:
            $arrayMerge: append
            $values: ["custom-feature"]
          tags:
            $arrayMerge: prepend
            $values: ["priority"]

Result:

  • features: ["core", "monitoring", "custom-feature"]
  • tags: ["priority", "production"]

All Strategies

# append — add after base items
features:
  $arrayMerge: append
  $values: ["new-item"]
# Base ["a", "b"] + overlay ["c"] = ["a", "b", "c"]

# prepend — add before base items
features:
  $arrayMerge: prepend
  $values: ["new-item"]
# Base ["a", "b"] + overlay ["c"] = ["c", "a", "b"]

# replace — completely replace base (default behavior)
features:
  $arrayMerge: replace
  $values: ["new-item"]
# Base ["a", "b"] + overlay ["c"] = ["c"]

Directives are stripped

Both $arrayMerge and $values are internal directives and do not appear in the final output.

Text File Merge Strategies

For text files with lines array content, merge strategies work the same way:

files:
  .gitignore:
    mergeStrategy: append
    content:
      - "node_modules/"
      - "dist/"

repos:
  - git: git@github.com:org/repo.git
    files:
      .gitignore:
        content:
          - "coverage/" # Appended to base

Result:

node_modules/
dist/
coverage/

Note

String content (not lines array) always uses replace strategy - the entire string is replaced.

Settings Array Merge

The $arrayMerge directive also works in settings overrides — rulesets, bypass actors, rules, conditions, and any other array field. This eliminates duplicating shared entries when a repo needs to add its own items.

Appending Bypass Actors

# Root — shared across all repos
settings:
  rulesets:
    pr-rules:
      bypassActors:
        - actorId: 2740          # Renovate
          actorType: Integration
          bypassMode: always

repos:
  # Adds a repo-specific actor without duplicating Renovate
  - git: git@github.com:org/repo.git
    settings:
      rulesets:
        pr-rules:
          bypassActors:
            $arrayMerge: append
            $values:
              - actorId: 2719952   # repo-specific bot
                actorType: Integration
                bypassMode: always

Result: bypassActors contains both Renovate (actorId 2740) and the repo-specific bot (actorId 2719952).

Appending Rules via Conditional Groups

settings:
  rulesets:
    pr-rules:
      rules:
        - type: pull_request
          parameters:
            requiredApprovingReviewCount: 1

groups:
  github-ci: {}

conditionalGroups:
  - when:
      allOf: [github-ci]
    settings:
      rulesets:
        pr-rules:
          rules:
            $arrayMerge: append
            $values:
              - type: required_status_checks
                parameters:
                  requiredStatusChecks:
                    - context: "summary / Check Results"

Repos with the github-ci group get both the pull_request rule and the required_status_checks rule. Repos without github-ci only get the pull_request rule.

Same syntax as file content

The $arrayMerge directive uses the same $arrayMerge + $values syntax in settings as in file content (see Inline Array Merge Directive above). Strategies: append, prepend, replace.

Example: Different Strategies per File

files:
  eslint.config.json:
    mergeStrategy: append # Extends will append
    content:
      extends: ["@company/base"]

  tsconfig.json:
    mergeStrategy: replace # Lib will replace entirely
    content:
      compilerOptions:
        lib: ["ES2022"]

repos:
  - git: git@github.com:org/frontend.git
    files:
      eslint.config.json:
        content:
          extends: ["plugin:react/recommended"]
      # Results in extends: ["@company/base", "plugin:react/recommended"]

      tsconfig.json:
        content:
          compilerOptions:
            lib: ["ES2022", "DOM"]
      # Results in lib: ["ES2022", "DOM"] (replaced)