Make minimal access users non-billable
Resolves Make Minimal Access users non-billable on Self-... (#584275 - closed).
What does this MR do and why?
This MR restores a subset of the work done at !210596 (merged) which was reverted by !216144 (merged).
In this new version, we make minimal access users non-billable for self-managed Premium instances. On self-managed Ultimate, and on Gitlab.com they already are non-billable.
References
- Make Minimal Access users non-billable on Self-... (#584275 - closed)
- Make `minimal access users` or `users not assig... (#330663 - closed)
- Make minimal access and users without membershi... (!210596 - merged)
Database review
README: This scope won't be used by Gitlab.com but by self-managed instances only. Gitlab.com's scale is not realistic here.
Query plan
Seq Scan on public.users (cost=0.00..110555461.53 rows=10706262 width=1669) (actual time=7.799..516277.842 rows=21953357 loops=1)
Filter: (NOT EXISTS(SubPlan 1))
Rows Removed by Filter: 29991
Buffers: shared hit=116828633 read=5116801 dirtied=158214 written=15911
WAL: records=168886 fpi=153369 bytes=1156371587
SubPlan 1
-> Aggregate (cost=0.56..4.90 rows=1 width=8) (actual time=0.021..0.021 rows=0 loops=21983348)
Filter: (max(members.access_level) = 5)
Rows Removed by Filter: 1
Buffers: shared hit=116828633 read=3748426 dirtied=59305 written=14288
WAL: records=54598 fpi=54460 bytes=429766566
-> Index Only Scan using index_members_on_user_id_and_access_level_requested_at_is_null on public.members (cost=0.56..4.72 rows=66 width=8) (actual time=0.017..0.020 rows=3 loops=21983348)
Index Cond: (members.user_id = users.id)
Heap Fetches: 3718859
Buffers: shared hit=116828633 read=3748426 dirtied=59305 written=14288
WAL: records=54598 fpi=54460 bytes=429766566
Settings: seq_page_cost = '4', effective_cache_size = '472585MB', jit = 'off', random_page_cost = '1.5', work_mem = '230MB'
Source: https://console.postgres.ai/gitlab/gitlab-production-main/sessions/48371/commands/145825
Screenshots or screen recordings
| Before | After |
|---|---|
![]() |
![]() |
![]() |
![]() |
How to set up and validate locally
Setup GDK in self-managed mode with a Premium license.
- Create a test user on the UI and it to a group with access level
Minimal Access - On the console, find the test user and verify billable status:
minimal_user = # Find user created above by ID
User.billable.include?(minimal_user) # Should be false
minimal_user.using_license_seat? # Should be false
- Check Admin UI:
- Go to Admin Area → Users
- Verify minimal access user has no "Is using seat" badge
- Click on user → Verify "Is using license seat: No"
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.



