| | |

GitLab 02 🦊 Setting Up Projects, Groups, and Subgroup Hierarchy

⏱️ Estimated read: 10 min | |

GitLab organizes work through a three-tier namespace hierarchy: groups, subgroups, and projects. A project contains the repository, issues, merge requests, and CI/CD pipelines. A group is a container for projects and other groups. A subgroup is a group nested inside another group. The hierarchy is not cosmetic—it determines how permissions inherit, how visibility is enforced, and how CI/CD runners and secrets are shared. The LFCS exam does not test GitLab, but the GitLab Certified Associate exam does, and the conceptual model is the same: the namespace is the permission boundary, and the project is the unit of work .

Key point: A project can belong to a user namespace (personal project) or a group namespace. Groups can contain subgroups nested up to 20 levels. Permissions granted at the group level are inherited by all subgroups and projects underneath. The visibility of a subgroup cannot be less restrictive than its parent group.


Why the hierarchy exists

The permission inheritance problem. If permissions were assigned per project, an organization with fifty projects and two hundred developers would require ten thousand permission entries. The group hierarchy reduces this: a developer joins a group, the group has a role on the parent, and the role inherits downward. When the developer leaves the group, the access is removed from every project underneath. The Source column in the Members list shows whether a member is a direct member of the group or an inherited member from a parent .

The visibility constraint problem. A private group cannot contain a public subgroup. The visibility of a child must be at least as restrictive as the parent. This prevents a situation where a public project exposes code that the parent group intended to keep private. The rule applies to projects as well: a project’s visibility must be at least as restrictive as its parent group’s visibility .

The organizational mapping problem. A company’s structure is rarely flat. A software organization has departments (Engineering, Product, QA), and each department has teams (Backend, Frontend, Mobile). The group hierarchy mirrors this: the top-level group is the organization, the subgroups are the departments, and the projects are the codebases. The Development group can contain Cool App Desktop and Cool App Mobile subgroups, each with its own projects .

The CI/CD resource problem. Runners registered to a parent group are available to jobs in subgroups. Secrets configured at the group level are available to subgroup jobs. This is the same inheritance principle applied to CI/CD: configure once at the highest level, use everywhere below .

The trade-off. The hierarchy is powerful but requires discipline. A group owner who creates a subgroup with the wrong visibility setting creates a constraint that cannot be undone without changing the parent. A member added to the parent group has access to every project underneath, which may be more access than intended. The hierarchy is a tool for scaling, not a substitute for planning.


a. Creating a group and a subgroup

A group is created from the top bar or the Groups page. It requires a name, a URL slug, and a visibility level. The visibility level is private, internal, or public. A private group is visible only to its members. An internal group is visible to any authenticated user. A public group is visible to anyone, including unauthenticated users .

# Create a top-level group
Top bar → Create new → New group
Group name: Development
Group URL: development-group
Visibility: Private
Create group

A subgroup is created from the parent group’s page. The “New subgroup” button appears in the upper-right corner. The subgroup’s visibility is constrained by the parent’s visibility. If the parent is private, the subgroup can only be private .

# Create a subgroup
Navigate to Development group
New subgroup
Subgroup name: Engineering
Visibility: Private (constrained by parent)
Create subgroup

The breadcrumb navigation at the top of the page shows the current location in the hierarchy. Clicking a parent group in the breadcrumb returns to that level. This is the primary navigation mechanism for nested groups .


b. Creating a project inside a group

A project is created from the group’s page or the top-level “Create new” menu. The project name becomes part of the URL. The project slug is the URL-safe version of the name. The visibility level is constrained by the parent group’s visibility.

# Create a blank project inside a subgroup
Navigate to Development → Engineering
Create project → Create blank project
Project name: Cool App API
Visibility: Private
Initialize repository with a README: checked
Create project

The project URL reflects the full namespace: gitlab.example.com/development/engineering/cool-app-api. The git clone command uses the same path. The namespace is not just a label; it is the address of the repository .

A project created in a personal namespace (the user’s own namespace, not a group) cannot be moved to a group without an explicit transfer operation. The group namespace is the correct location for any project that will be shared with a team.


c. Membership inheritance and role overrides

When a member is added to a group, the member is added to every subgroup and project underneath. The role is inherited. A member added to the Development group as a Developer has the Developer role on every project in Development, Engineering, and any other subgroup.

# Add a member to a group
Navigate to Development group
Manage → Members → Invite members
Username: alexsmith
Role: Developer
Invite

The Source column in the member list shows Direct for members added directly to the group, and the parent group name for inherited members. A member added directly to a subgroup can have a higher role than the inherited role, but not a lower one. The role in a subgroup can only be overridden with a higher role, not a lower one .

# Override a role in a subgroup
Navigate to Development → Engineering
Manage → Members → Invite members
Username: alexsmith
Role: Maintainer (higher than inherited Developer)
Invite

The inherited Developer role is overridden by the Maintainer role in the Engineering subgroup. The member remains a Developer in the parent Development group and in other subgroups, but is a Maintainer in Engineering and its projects.


Complete Example Session

# ============================================
# PART 1: CREATE A TOP-LEVEL GROUP
# ============================================

Top bar → Create new → New group
Group name: Development
Group URL: development-group
Visibility: Private
Create group
# ============================================
# PART 2: CREATE A SUBGROUP
# ============================================

Navigate to Development
New subgroup
Subgroup name: Engineering
Create subgroup
# ============================================
# PART 3: CREATE A NESTED SUBGROUP
# ============================================

Navigate to Development → Engineering
New subgroup
Subgroup name: Backend
Create subgroup
# ============================================
# PART 4: CREATE A PROJECT
# ============================================

Navigate to Development → Engineering → Backend
Create project → Create blank project
Project name: API Service
Initialize repository with a README: checked
Create project
# ============================================
# PART 5: ADD A MEMBER TO THE GROUP
# ============================================

Navigate to Development
Manage → Members → Invite members
Username: alexsmith
Role: Developer
Invite
# ============================================
# PART 6: VERIFY INHERITANCE
# ============================================

Navigate to Development → Engineering → Backend → API Service
Manage → Members
# alexsmith appears with Source: Development
# Role: Developer (inherited)
# ============================================
# PART 7: OVERRIDE ROLE IN SUBGROUP
# ============================================

Navigate to Development → Engineering → Backend
Manage → Members → Invite members
Username: alexsmith
Role: Maintainer
Invite
# ============================================
# PART 8: VERIFY THE OVERRIDE
# ============================================

Navigate to Development → Engineering → Backend → API Service
Manage → Members
# alexsmith appears with Source: Backend
# Role: Maintainer (direct, overrides inherited Developer)
# ============================================
# PART 9: CHECK VISIBILITY CONSTRAINTS
# ============================================

Navigate to Development → Settings → General
# Visibility: Private
# A public subgroup cannot be created under a private parent.

The nine parts trace the hierarchy: top-level group, subgroup, nested subgroup, project creation, member addition, inheritance verification, role override, override verification, and visibility constraint.


Quick Reference

Hierarchy Levels

LevelPurposeContains
GroupOrganization or departmentSubgroups, projects
SubgroupTeam or sub-departmentSubgroups, projects
ProjectRepository and work itemsCode, issues, MRs, CI/CD

Visibility Levels

LevelVisible To
PrivateMembers only
InternalAuthenticated users
PublicAnyone

Role Hierarchy

RoleKey Permissions
GuestView issues, comment
ReporterView code, clone
DeveloperPush, create branches
MaintainerManage settings, merge
OwnerManage members, delete

Membership Sources

SourceMeaning
DirectAdded directly to this group/project
InheritedAdded to a parent group
SharedMember of an invited group

Best Practices

✅ Do This:

# Add members to the highest group possible
<!-- Permissions inherit downward; fewer entries -->
# Use subgroups to mirror the organization
<!-- Development → Engineering → Backend -->
# Check the Source column
<!-- Verify inherited vs direct membership -->

❌ Don’t Do This:

# Add members directly to every project
<!-- Duplicates entries; difficult to audit -->
# Create a public subgroup under a private parent
<!-- Constraint prevents this; plan visibility first -->
# Override a role with a lower role in a subgroup
<!-- Only higher roles can override inherited roles -->

Common Pitfalls

PitfallWhy It HappensFix
Cannot change subgroup visibilityParent is more restrictiveChange parent first
Member has unexpected accessInherited from parentCheck Source column
Cannot lower role in subgroupInherited role is the floorRemove from parent, add to subgroup
Cannot create subgroupRole too lowMaintainer or Owner required
Project URL wrongCreated in personal namespaceTransfer to group namespace

Real-World Examples

1. Create Group

Create new → New group
Group name: Development
Visibility: Private

2. Create Subgroup

Navigate to Development → New subgroup
Subgroup name: Engineering

3. Create Nested Subgroup

Navigate to Engineering → New subgroup
Subgroup name: Backend

4. Create Project

Navigate to Backend → Create project
Project name: API Service

5. Add Member

Development → Manage → Members → Invite
Role: Developer

6. Verify Inheritance

API Service → Manage → Members
Source: Development

7. Override Role

Backend → Manage → Members → Invite
Role: Maintainer

8. Check Visibility

Development → Settings → General
Visibility: Private

9. Filter Members by Source

Members → Filter → Membership → Inherited

10. Remove Member

Development → Manage → Members → Remove
Also remove direct membership from subgroups

Visual

Namespace Hierarchy

┌──────────────────────────────────────────────┐
│  Development (top-level group)               │
│  Visibility: Private                         │
└──────────────────┬───────────────────────────┘
                   │
        ┌──────────┴──────────┐
        │                     │
        ▼                     ▼
┌───────────────┐     ┌───────────────┐
│  Engineering  │     │  Product      │
│  (subgroup)   │     │  (subgroup)   │
└───────┬───────┘     └───────────────┘
        │
        ▼
┌───────────────┐
│  Backend      │
│  (subgroup)   │
└───────┬───────┘
        │
        ▼
┌───────────────┐
│  API Service  │
│  (project)    │
└───────────────┘

Membership Inheritance

┌──────────────────────────────────────────────┐
│  Development: alexsmith = Developer (Direct) │
└──────────────────┬───────────────────────────┘
                   │
                   ▼
┌──────────────────────────────────────────────┐
│  Engineering: alexsmith = Developer (Inherited)│
└──────────────────┬───────────────────────────┘
                   │
                   ▼
┌──────────────────────────────────────────────┐
│  Backend: alexsmith = Maintainer (Direct)    │
│  (overrides inherited Developer)             │
└──────────────────┬───────────────────────────┘
                   │
                   ▼
┌──────────────────────────────────────────────┐
│  API Service: alexsmith = Maintainer         │
└──────────────────────────────────────────────┘

Summary

ItemValue
HierarchyGroup → Subgroup → Project
Max nesting20 levels
Visibility levelsPrivate, Internal, Public
Visibility constraintChild ≥ parent restrictiveness
Member inheritanceGroup members inherit to all subgroups/projects
Role overrideOnly higher roles can override inherited
Project URLgitlab.example.com/group/subgroup/project

Key takeaways:

  • The namespace is the permission boundary. A project inherits the permissions of its group. A subgroup inherits the permissions of its parent. Adding a member to the top-level group grants access to every project underneath.
  • Visibility is constrained by the parent. A private group cannot contain a public subgroup. The visibility of a child must be at least as restrictive as the parent. This prevents accidental exposure of private code .
  • The Source column shows inheritance. A member’s Source is Direct if added to that group, or the parent group name if inherited. This is the diagnostic tool for permission confusion .
  • Roles can be overridden only with higher roles. A member with Developer inherited from a parent cannot be given Reporter in a subgroup. They can be given Maintainer, which overrides the inherited role.
  • The project URL reflects the hierarchy. The git clone path is the same as the namespace path. A project in development/engineering/backend/api-service is addressed by that full path .

Remember: The hierarchy is the foundation of GitLab’s permission model. The group is the organizational unit. The subgroup is the team unit. The project is the work unit. Permissions flow downward. Visibility is constrained upward. The Source column is the audit tool. The breadcrumb is the navigation tool.

Was this helpful?


Stop using slow, ad-bloated tool sites! 🤮

🔎 Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)

⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free

🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!