The reason people ask for custom roles is almost always the same: somebody needs to do one thing that requires admin, and admin gives them everything.
Custom roles solve that specific problem well. They also invite a design where every request produces a new role, and an enterprise with forty roles has replaced a permissions problem with a taxonomy problem.
The short answer
Section titled “The short answer”Two distinct mechanisms.
Custom repository roles are “a configurable set of permissions with a custom name you choose”, granting access to specific repositories. GitHub documents that “Only organizations that use GitHub Enterprise Cloud can create custom repository roles”, with up to 20 per organisation — or up to 5 on GitHub Enterprise Server versions earlier than 3.19.
Custom organisation roles are “a way to grant an organization member the ability to administer certain subsets of settings without granting full administrative control of the organization and its repositories.”
The critical difference: a custom repository role applies to the repositories it is granted on. An organisation role granting repository permissions grants them across the organisation — GitHub is explicit that “Repository permissions grant access to all current and future repositories in the organization.”
That “all current and future” clause is the one to read twice, because it means an organisation role with repository permissions is a standing grant over repositories that do not exist yet.
Custom repository roles
Section titled “Custom repository roles”Built from a base role plus additional permissions. The four inheritable bases, in GitHub’s own descriptions:
- Read — “Non-code contributors who want to view or discuss your project”
- Triage — “Contributors who need to proactively manage issues and pull requests without write access”
- Write — “Organization members and collaborators who actively push to your project”
- Maintain — “Project managers who need to manage the repository without access to sensitive or destructive actions”
Then add specific permissions on top. Examples GitHub documents include managing webhooks, setting milestones, handling code scanning alerts, dismissing or reopening Dependabot alerts, managing GitHub Pages settings, and pushing commits to protected branches.
The pattern that justifies a custom role: a group needs exactly one capability that their base role lacks, and the alternative is granting them the next base role up — which gives them a great deal more.
The canonical example is security triage. A security team needs to dismiss code scanning and Dependabot alerts across the estate. Without a custom role, that means admin. With one, it means Read plus two alert permissions.
The second is release management. A release engineer needs to push to a protected branch during a release. Without a custom role, that means bypass on every ruleset or admin. With one, it is a named permission on a named role.
Custom organisation roles
Section titled “Custom organisation roles”These grant administration of subsets of organisation settings without full organisation ownership.
Which addresses the other version of the same problem: somebody needs to manage one category of organisation setting, and the alternative is making them an organisation owner.
They can also grant repository access via base roles — Read, Write, Triage, Maintain or Admin — across the organisation.
Use the settings-administration capability freely; use the organisation-wide repository grant sparingly. The first is genuinely least-privilege: it narrows what an administrator can touch. The second is the opposite — it is a broad grant expressed as a role, covering every repository the organisation will ever have.
Enterprise owners can define standard custom organisation roles for organisation owners to assign, which is how you get a consistent role vocabulary across many organisations rather than each inventing its own.
Why fewer roles is better
Section titled “Why fewer roles is better”The design instinct that matters most, and the one that runs against how requests arrive.
Every role is a thing somebody must understand. When a permission problem occurs, the debugging question is “which role does this person have and what does it grant”, and forty roles makes that question expensive.
Every role decays. A role created for a team that reorganised is still assigned, still granting, and nobody knows whether removing it is safe.
Roles multiply from requests. Each individual request is reasonable. The aggregate is a taxonomy nobody designed.
The limits are real — 20 custom repository roles per organisation — but they are not the binding constraint. The binding constraint is comprehension.
The test before creating a role: can an existing role serve, possibly with slightly more permission than strictly minimal? A slightly-too-broad role that people understand is frequently better governance than a precisely-minimal role that nobody can reason about.
Designing a role set
Section titled “Designing a role set”Aim for a handful, each with a stated purpose.
Start from the base roles. Read, Triage, Write, Maintain and Admin cover most needs, and most organisations should use them for most people.
Add roles only for recurring exceptions. A capability requested once is an exception; requested five times by different teams, it is a role.
Name roles for the function, not the team. security-triage outlives the security team’s current name; appsec-team-role does not.
Document what each role is for and who should have it, in a place that is found before the role is assigned rather than after.
Review annually. Which roles exist, who has them, and whether the reason still applies.
A workable starting set:
| Role | Base | Adds | For |
|---|---|---|---|
security-triage | Read | Dismiss code scanning and Dependabot alerts | Security engineers, across the estate |
release-manager | Write | Push to protected branches | Named release engineers, on release repositories |
integration-admin | Maintain | Manage webhooks | Platform team, on integration repositories |
Three roles, each with a stated need. Most enterprises do not need more than five.
Standing privilege versus just-in-time
Section titled “Standing privilege versus just-in-time”The framing that determines whether a role set improves security or merely reorganises it.
A role is standing privilege. Somebody has it all the time, whether or not they are using it. Reducing the breadth of standing privilege is good; it does not change the fact that it is standing.
Which matters most for the powerful roles. A release manager who can push to protected branches has that capability every day, and needs it for perhaps two hours a month.
The alternatives, in increasing order of effort:
Bypass on rulesets rather than a role. A ruleset bypass restricted to pull requests only is narrower than a push permission, and it is visible in the ruleset rather than buried in a role definition.
An automation identity instead of a person. If the capability is exercised by a process — a release pipeline, a bot — grant it to a GitHub App with a scoped installation rather than to a human role. The app’s permissions are explicit, its actions are attributable, and no person carries the privilege. See machine identities.
A time-bounded grant. Assign the role, do the work, remove it. Crude, and it works. It requires a process that actually removes, which is the part that fails.
A delegated approval flow. For lifecycle actions, repository policies offer delegated bypass, where the action is requested and approved rather than pre-authorised. Documented as public preview, and the right shape for the problem.
The honest position: GitHub’s role model is fundamentally standing-privilege, and there is no built-in just-in-time elevation for repository permissions. What you can do is keep the powerful roles small in membership, review them frequently, and move as much as possible to automation identities where the privilege belongs to a process rather than a person.
Roles, teams and grants
Section titled “Roles, teams and grants”Three mechanisms that interact, and confusing them is the most common source of permission surprise.
A role defines a set of permissions. It grants nothing on its own.
A grant assigns a role to a team or a person on a repository. This is where access actually comes from.
A team is who. Teams should be the subject of grants, essentially always, because individual grants are unmaintainable and invisible at review time.
The composition is: team plus role plus repository. The security team has the security-triage role on all repositories in the organisation. The payments team has Write on the payments repositories.
Base permission is the floor. Whatever the organisation’s base permission is, every member has at least that on every repository, and grants add to it. A role cannot reduce below the base permission — which is why base permission is the setting to get right first. See enterprise account architecture.
Which means a “restricted” role does not restrict. Roles add capability; they never remove it. If somebody has too much access, the fix is the base permission or the grant, not a narrower role.
Rolling out a role set across many organisations
Section titled “Rolling out a role set across many organisations”Custom repository roles are defined per organisation, which creates a consistency problem the moment you have more than one.
A role named security-triage in three organisations may grant three different things. Nothing prevents it, and nobody notices until an incident response finds that the security team can dismiss alerts in two organisations and not the third.
Enterprise-defined standard organisation roles address part of this: enterprise owners can define roles that organisation owners assign, so the definition is shared rather than replicated.
For custom repository roles, the answer is automation. Define the role set once, as data, and apply it to every organisation through the API. Reconcile on a schedule and report divergence.
Report, do not silently correct. An organisation that changed a role definition may have had a reason. A reconciliation job that overwrites without warning destroys the reason and the record of it.
Version the definitions. A role’s permission list is exactly the kind of thing that should change through a reviewed pull request, with a history showing when a permission was added and by whose approval.
And keep the naming identical across organisations, even where the definitions must differ. A name that means different things in different places is worse than two different names.
The requests you will receive
Section titled “The requests you will receive”Anticipating these makes the design conversation easier, because each has a standard answer.
“I need admin to change a setting.” Ask which setting. Frequently the answer is a permission that already exists in the custom-role catalogue, or an organisation setting that a custom organisation role can cover.
“The security team needs access to everything.” They need to read everything and dismiss alerts. Read plus alert permissions, not Admin. The distinction is the difference between a triage capability and a fleet-wide write grant.
“Our contractors need to work in these repositories but shouldn’t see the rest.” That is a base permission and outside-collaborator question, not a role question. See internal repositories.
“The release process is blocked by branch protection.” Usually a ruleset bypass for an automation identity, not a human role.
“Auditors need access.” Read access to specific repositories, time-bounded, granted to a team. Auditors almost never need write, and granting it creates a control problem in the middle of an audit.
“Support needs to reopen issues.” Triage. This is what the Triage base role exists for, and it is frequently overlooked because people jump from Read straight to Write.
The pattern across all of them: the request names a role, and the underlying need names a capability. Asking what the person is trying to do resolves most of these without creating anything.
Reviewing what roles actually grant
Section titled “Reviewing what roles actually grant”The audit that surprises people.
List every custom role and its permissions. Compare against what people believe it grants. Roles drift as permissions are added over time.
List every assignment. Who has which role on what. Individual assignments are the ones that decay.
Check organisation roles with repository permissions specifically. These are the broad grants, and they are the ones most likely to have been created without the “all current and future repositories” implication being understood.
Cross-check against leavers. A role assignment survives if offboarding removes organisation membership but the assignment was to an individual on a repository. See access reviews and offboarding.
Look for roles with no assignments. Either the need went away, or the role was created and never used. Both are candidates for deletion.
Look for people with several roles. Frequently the residue of role changes, and frequently more access than any single role was intended to give.
What roles cannot do
Section titled “What roles cannot do”Setting expectations, because roles are frequently proposed as the answer to problems they cannot address.
They cannot restrict. There is no role that grants less than the organisation’s base permission. If everybody has Read on everything and you need somebody to have less, the answer is base permission or a separate organisation, not a role.
They cannot express conditions. A role cannot say “Write, but only on weekdays” or “Admin, but only during an incident”. Permissions are unconditional.
They cannot scope by branch. A role grants repository-level permissions; branch-level control is rulesets, and the two are configured separately and interact in ways worth testing.
They cannot span organisations. A custom repository role is defined and assigned within one organisation.
They cannot grant enterprise-level administration. Enterprise owner is not decomposable into custom roles in the way organisation ownership is.
They cannot make an outside collaborator into a member. Outside collaborators can be granted roles on repositories, but the collaborator boundary — including the inability to read internal repositories — is not something a role changes.
Knowing the boundaries prevents a common failure: a governance design that assumes roles will handle something they cannot, discovered during implementation, with the compensating control never built.
Roles and the audit trail
Section titled “Roles and the audit trail”Worth noting because it is the part most relevant to compliance work.
Role creation, modification and assignment are recorded in the audit log. That gives you the record of who granted what, and when.
Role usage is largely not distinguishable. The log records that a person dismissed an alert, not that they did so by virtue of a particular role. Which is usually fine — the action is what matters — but it means “prove that this role was necessary” is a harder question than “prove who has it”.
Permission changes are the events to alert on. A role gaining a permission, or a person gaining a powerful role, are both low-volume and high-consequence. Streaming the audit log makes both alertable; see audit log streaming.
A periodic export of the role-and-assignment state is the evidence artifact most access-control control objectives actually want. It is a small amount of automation and it turns an audit request that takes a week into one that takes an hour. See compliance evidence.
Keep the exports. A point-in-time snapshot answers “who had access on this date”, which is the question that arrives after an incident and cannot be reconstructed from current state.
Common mistakes
Section titled “Common mistakes”Creating a role per request. The aggregate is a taxonomy nobody designed.
Organisation roles with broad repository permissions. “All current and future repositories” is a very large grant.
Assigning roles to individuals. Invisible at review time and survives team changes.
Naming roles after teams. They outlive the team name.
Expecting a role to restrict. Roles add capability; base permission sets the floor.
Never reviewing assignments. They are the part that decays.
Using Admin because a specific permission is missing. That is what custom roles exist for.
Assuming custom repository roles are available. GitHub documents them as Enterprise Cloud only.
A worked design
Section titled “A worked design”Take a concrete enterprise: four organisations, 1,200 repositories, a central security team, a platform team and thirty product teams.
Base permission: read. Everybody can read everything in their organisation. This is the decision that determines how much the rest has to do — with read as the floor, no role needs to grant read access, and every role is about a specific capability.
Product teams get Write on their own repositories, granted to the team, using the standard Write base role. No custom role needed, and this covers the overwhelming majority of all access in the enterprise.
Maintain for team leads on their own repositories. Again standard — GitHub describes Maintain as being for people who “manage the repository without access to sensitive or destructive actions”, which is exactly the description of a team lead.
One custom repository role: security-triage. Base Read, plus dismissing code scanning and Dependabot alerts. Granted to the security team across all repositories. This is the role that would otherwise have been Admin.
One custom organisation role for the platform team, granting administration of the organisation settings they own — apps, webhooks, Actions configuration — without organisation ownership. No repository permissions attached.
Organisation ownership: four people. One per organisation, plus a documented deputy.
Release access: not a role. Release pipelines run as GitHub Apps with scoped installation permissions and a ruleset bypass restricted to those apps. No human has standing permission to push to a protected branch.
Total: two custom roles. Everything else is base roles, teams and one automation identity pattern. This is what a well-designed role set looks like at 1,200 repositories, and the instinct that it must be more complicated is the instinct to resist.
Mental model
Section titled “Mental model”A role is a vocabulary word for a capability. Teams are who, grants are where, roles are what. The goal is a small vocabulary that people can hold in their heads — because the cost of a role is not the permission it grants but the reasoning it requires every time somebody debugs access.
What you learned
Section titled “What you learned”- Custom repository roles are a configurable permission set, limited to 20 per organisation, and are documented as Enterprise Cloud only
- They build on Read, Triage, Write or Maintain, adding specific permissions such as alert dismissal or pushing to protected branches
- Custom organisation roles grant administration of subsets of organisation settings without full ownership
- An organisation role with repository permissions grants them across all current and future repositories in the organisation
- Enterprise owners can define standard organisation roles for consistency across organisations
- Roles add capability and never restrict it; base permission sets the floor
- Grants should be to teams, not individuals
- Fewer roles is better, because the real cost is comprehension rather than the documented limit
- Roles with no assignments and people with several roles are both review findings
Exercise
Section titled “Exercise”Use an organisation you administer.
-
List every custom role defined. For each, state its purpose in one sentence.
-
For each role, list its permissions. Predict: does any grant more than you expected?
-
Find any organisation role with repository permissions. Count the repositories it covers today.
-
List every role assignment. Separate team assignments from individual ones.
-
Find a role with no assignments. Decide whether to delete it.
-
Find a person with more than one role. Work out what they can actually do.
-
Check your organisation’s base permission. Predict: how much of the access you found comes from grants versus from the base?
-
Design the smallest role set that covers your actual recurring needs.