The CODEOWNERS feature allows you to determine individuals responsible for specific parts of the repository. Users and groups can be determined as responsible parties. Changes affecting files specified in CODEOWNERS must be approved by the code owners.

Using CODEOWNERS helps:

  • Require approval from domain experts for important directories.
  • Simplify the process of finding those responsible for a specific section of code.

CODEOWNERS complements the approval rules mechanism, but does not replace it. Unlike approval rules, which are set manually in the UI, CODEOWNERS works through the CODEOWNERS file in the repository.

How CODEOWNERS works

CODEOWNERS is a text file in the repository. Deckhouse Code uses it to determine the owners of files involved in a merge request.

It is searched in three places (in order of priority):

  1. ./CODEOWNERS
  2. ./docs/CODEOWNERS
  3. ./.gitlab/CODEOWNERS

Only the first file found is used.

If there are several files in the project and you are currently viewing a non-priority file, you will see a corresponding message.

Non-priority file

Validating the CODEOWNERS file

Validation helps you find errors in the file during editing.

If the file is valid, the following message is displayed:

Valid file

If the file is invalid, the problematic lines and the type of error will be displayed:

Invalid file

There are four types of validation errors

  • Owners either do not have project access or their access level not enough: At least one of the owners does not have sufficient rights in the project.
  • Spaces in path: If the path contains spaces, they must be escaped with the \ character.
  • Zero owners: No owners are specified.
  • Not a closed section: The closing section character ] is missing.

Where CODEOWNERS is used

If the MR modifying the file falls under the CODEOWNERS rules, approval must be obtained from the owners.

CODEOWNERS format

Rule string:

<path or pattern> <list of owners>

Owners:

  • @user
  • @group
  • @group/subgroup
  • Roles: @@developer, @@maintainer, @@owner

Examples

# Owner of all files.
* @default-team

# README.md only in the root directory.
/README.md @docs-team

# All Ruby files.
*.rb @backend-team

# The entire config directory.
/config/ @devops

# README.md anywhere.
README.md @docs

Path patterns

Deckhouse Code uses wildcards:

  • *: Any characters except /.
  • **: Matches multiple directory levels.
  • /dir/: Only the specified directory.
  • *.md: All Markdown files.
  • /config/**/*.rb: All Ruby files inside config/* at all levels.

Pattern examples

/docs/*       @docs-one      # one level
/docs/**      @docs-two      # recursively
/app/**/*.rb  @ruby-team

CODEOWNERS sections

In the CODEOWNERS file, sections are named areas that are analyzed separately and always applied. Until you define a section, Deckhouse Code treats the entire CODEOWNERS file as a single section.

Features of using CODEOWNERS:

  • Deckhouse Code treats entries without sections, including rules defined before the first section, as a separate, unnamed section.
  • Each section processes its rules separately.
  • If the file path matches multiple entries within a single section, only the last matching entry in that section is used.
  • If the file path matches entries in multiple sections, the last matching entry in each section is used.

For example, in a CODEOWNERS file with the following sections defining owners for README:

* @root

[README Owners]
README.md @user1 @user2
internal/README.md @user4

[README other owners]
README.md @user3

Owners for README.md in the root directory:

  • @root: From the unnamed section.
  • @user1 and @user2: From the [README Owners] section.
  • @user3: From the [README other owners] section.

Owners for internal/README.md:

  • @root: From the unnamed section.
  • @user4: From the [README Owners] section. (Both README.md and internal/README.md match the section rules, but only the last matching entry in this section is used).
  • @user3: From the [README other owners] section.

In the merge request widget, each code owner is displayed under their own label.

Codeowners example

Detailed example: complex combination of sections

Below is an example of a real industrial file showing:

  • Sections with different numbers of approvals
  • Redefining owners
  • Optional sections
  • Exceptions
  • Inheritance of sections with identical names
# Global settings.
* @fallback-team
!*.lock                    # lock files do not require approval
!**/generated/**           # automatic generation

[Backend][2] @backend-core
# Requires 2 approvals from backend-core for any Ruby code.
app/**/*.rb

# But for critical models, we define a different order.
app/models/**/*.rb @backend-core @security-team

# But this model is an exception; the owner is different.
app/models/legacy/**/*.rb @migration-team

[Backend]
# Section update: Backend now also includes SQL.
db/**/*.sql @db-team

[Ruby Optional]
# Additional highlighting for owners, approvals are NOT required.
^[Ruby Optional]
*.rb @ruby-advisors

[Frontend][3]
# The UI requires 3 approvals.
*.vue @frontend-team
*.js  @frontend-team

# Redefining: specific file → specific person.
frontend/critical_entry.vue @frontend-lead

[Docs]
*.md @technical-writers

[Docs]
# Redefining: README always belongs to docs-lead.
README.md @docs-lead

Things to note about the example:

  • The [Backend] section is declared twice → Deckhouse Code will combine it.
  • [Backend][2] @backend-core specifies 2 mandatory approvals.
  • [Frontend][3] requires 3 approvals from the frontend.
  • [Ruby Optional] is marked as optional — owners are visible, but their approval is not required.
  • The exceptions !*.lock and !**/generated/** mean that these files do not require approvals at all.

Exclusions (!)

Used to exclude files within a section:

* @default
!package-lock.json
!**/generated/**

After exclusion, the file cannot be re-included in the same section.

Rule processing order

Rules are processed in the following order:

  • Deckhouse Code reads the file from top to bottom.
  • Within a single section, rules with the same path override previous ones.
  • If a file fits into several sections, the owners from all these sections are added.
  • Sections do not override each other: They are independent.

Who can be an owner (eligible owners)

1. Users (via @username)

A user is considered a valid owner if:

  • They have direct membership in the project (Developer, Maintainer, or Owner).
  • They have membership in a project group (including inherited: project group, parent groups, ancestors of parent groups).
  • They are a direct or inherited member of a group that is directly invited to the project.
  • They are a direct but not inherited member of a group that is invited to the project group.
  • They are a direct but not inherited member of a group that is invited to an ancestor of the project group.

To sum up, all users who are displayed on the project participants page with the role of Developer or higher are eligible.

A user is not considered an owner if:

  • They are blocked.
  • Their access has been revoked.
  • Their role is lower than Developer.

2. Groups (via @group or @group/subgroup)

A group can be an owner only if:

  • It is directly invited to the project with the Developer+ role (via “Invite a group”).
  • Only direct members of this group are considered owners.

Inherited members of parent groups are not considered owners.

3. Roles (via @@role)

Format:

@@developer
@@maintainer
@@owner

Features:

  • Only direct project participants are taken into account.
  • Group members are not included in the calculation.
  • Roles are not inherited from each other (@@developer does NOT include maintainers).

You can specify multiple roles in one line:

file.md @@developer @@maintainer

Interaction with approval rules

CODEOWNERS and approval rules work independently, but their requirements are cumulative.

Example:

  • The Security rule requires 1 approval.
  • The [Backend][2] section requires 2 approvals.
  • MR changes the backend file.

Result: 3 approvals are required.

Disabling CODEOWNERS checks

CODEOWNERS checks, which are enabled by default in Deckhouse Code, can be disabled at the project level. This is useful when a project has a CODEOWNERS file, but approvals from code owners are not required.

To disable these checks, navigate to “Project” → “Settings” → “Merge requests” → the additional approval rule settings, and select “Disable Code Owners approval checks”.

Setting "Disable Code Owners approval checks"

Once the checks are disabled, CODEOWNERS are skipped across the whole project:

  • Merge requests are not blocked by missing approvals from code owners.
  • Code owners are not defined for the changed files — the list of applicable entries is empty.
  • Enabling or disabling the setting is immediately applied to already open merge requests.

Validation of the CODEOWNERS file syntax keeps working. The file can be validated even when the checks are disabled.

Automatically assigning code owners as reviewers

Code owners matching the changed files can be automatically assigned as reviewers of a merge request.

To enable that, navigate to “Project” → “Settings” → “Merge requests” → “Automatic reviewer assignment”, and select “Automatically assign code owners as reviewers”.

Setting "Automatically assign code owners as reviewers"

This setting is disabled by default. When it is enabled, code owners are assigned as reviewers:

  • When a merge request is created as ready (not a draft).
  • When a draft merge request is marked ready.

Restrictions applied when the automatic assignment is enabled:

  • Assignment is not performed for drafts.
  • If a merge request already has reviewers, automatic assignment is skipped — manually assigned reviewers are kept.
  • The merge request author can never be assigned as a reviewer.
  • Only users with read access to the merge request are assigned.
  • If the project forbids to assign multiple reviewers, only the first code owner is assigned.

Formatting recommendations

When formatting the CODEOWNERS file, follow these recommendations:

  • First, set broad rules (* @team). Then specify more detailed rules (app/**/*.rb @backend-team).
  • Use sections for better structure and clarity.
  • Avoid duplicates — the last rule in a section takes precedence.
  • Optional sections are useful for highlighting experts without mandatory approvals.

Example of the final file

# Global owners.
* @default-team

# Exclusions.
!yarn.lock
!**/generated/**

[Backend][2]
app/**/*.rb @backend-core

[Frontend][3]
*.vue @frontend-team
*.js @frontend-team

^[Docs]
*.md @docs-team

[Critical Overrides]
/config/production.yml @ops-lead