Quotas
Quotas limit how much each user or organization may store, and in Arbinel also how much CI time and download traffic they may use. Forgejo’s quota page documents the API calls but does not explain how groups and rules combine. Most configuration mistakes come from that combination.
Enable quotas
Section titled “Enable quotas”| Key | Default | Meaning |
|---|---|---|
[quota] ENABLED |
false |
Turns quota on. While it is off, nothing is limited and every Arbinel quota feature is inert. |
[quota] DEFAULT_GROUPS |
empty | Quota groups that apply to an owner who has been put in no group explicitly. |
[quota.default] TOTAL |
-1 |
The size:all limit for an owner who ends up in no group at all. -1 is unlimited. |
Forgejo stores groups and rules in the database, not in app.ini.
You manage them through the admin API under /api/v1/admin/quota, with an access token of a site administrator that has the admin scope.
Browse the endpoints at /api/swagger on your instance.
How quotas work
Section titled “How quotas work”Forgejo’s quota has three parts.
- A subject is something that can be counted, such as
size:repos:allorsize:git:lfs. Forgejo lists its subjects in the configuration cheat sheet. Subjects form a tree undersize:all. For example,size:assets:attachments:issuesis a child ofsize:assets:attachments:all, which is a child ofsize:assets:all. - A rule is a named limit on the sum of one or more subjects.
The limit is a plain number in the subject’s unit, bytes for
size:subjects, and-1means unlimited. A rule with the subjectssize:repos:allandsize:git:lfsand a limit of 1 GiB limits repositories and LFS together to 1 GiB. - A group is a named set of rules. Users and organizations are members of groups. An organization has its own quota, separate from the quotas of its members.
Which groups apply to an owner
Section titled “Which groups apply to an owner”Forgejo selects one set of groups per owner, in this order:
- The groups the owner was added to explicitly, if there is at least one.
- Otherwise, the groups in
[quota] DEFAULT_GROUPS. - Otherwise, no group, and the single rule
size:all <= [quota.default] TOTALapplies.
Adding an owner to any group explicitly means DEFAULT_GROUPS no longer applies to them.
To give an owner a premium group and keep the default group’s rules for everything the premium group does not cover, add them to both groups.
How a request is checked
Section titled “How a request is checked”Before a write, Forgejo asks whether the owner may add more of one subject, such as size:assets:attachments:releases for a release upload.
- Inside one group, a rule matches when it names the subject or one of its parents in the subject tree. If several rules match, the strictest one decides.
- Across groups, the most generous answer wins. One group that allows the write is enough.
- A group in which no rule matches the subject does not allow it. If none of the owner’s groups matches, the write is refused.
The last point is a common source of mistakes.
A group that only has a rule on size:repos:all refuses every attachment, package and artifact upload of its members, because none of those subjects is a child of size:repos:all.
Give every group a rule on size:all, or on each branch of the tree you mean to allow.
The check is soft: it happens before the operation starts, and an operation that has started finishes. A push can take an owner past their limit, and the next write that needs space is refused.
Rules are shared between groups
Section titled “Rules are shared between groups”Rules are stored once, by name, and a group only refers to them.
- Editing a rule with
PATCH /api/v1/admin/quota/rules/{rule}changes it in every group that uses it. - Creating a group with an inline rule whose name already exists reuses the existing rule and ignores the limit and subjects you sent.
Name rules after what they mean, such as free-storage or pro-storage, not after a group.
Set up free and pro tiers
Section titled “Set up free and pro tiers”This sets up a free tier of 1 GiB for everyone and a pro tier of 20 GiB for selected owners.
-
Create both groups with their rules.
-
Make
freethe default. -
Put a pro owner in both groups, so they keep the free allowance if they ever leave
pro.POST /api/v1/admin/users/{username}/quota/groupsreplaces the owner’s groups. To add or remove one group, usePUTorDELETEon/api/v1/admin/quota/groups/{group}/users/{username}. Both work for organizations, with the organization’s name in place of the user name. -
Check the result with
GET /api/v1/admin/users/alice/quota. Users see their own quota withGET /api/v1/user/quota, and organization quotas are atGET /api/v1/orgs/{org}/quota.
Alice is now in free and pro.
For any upload, pro-storage allows up to 20 GiB, and the most generous group wins, so her limit is 20 GiB.
Forgejo can also sync group membership from an OAuth2 claim, which Forgejo’s quota page describes.
Arbinel additions
Section titled “Arbinel additions”Arbinel adds new subjects and units, and features that use the same groups and rules.
| Feature | Subjects | Turn it on | Page |
|---|---|---|---|
| CI time | time:ci:all, time:ci:actions, time:ci:external, time:ci:class:linux, time:ci:class:windows, time:ci:class:macos |
[quota.ci] ENABLED |
CI quota |
| Download traffic | egress:all |
An edge proxy that reports traffic | Egress quota |
| Storage warnings | existing size: subjects |
On by default once quota is on | below |
| Quota grants | any subject | [quota.grants] ENABLED |
Quota grants |
| Paid add-ons | any subject | [billing] ENABLED |
Billing |
Each subject is counted in one unit: bytes stored, seconds of CI time, or bytes downloaded.
- A rule may only name subjects of one unit.
The API refuses a rule that mixes them with
422. - A group only applies to the units its rules use.
A group with only a
time:ci:allrule does not refuse its members’ pushes, and a group with onlysize:rules does not refuse their CI jobs. - When none of an owner’s groups has a rule in a unit, the instance-wide fallback for that unit applies.
For bytes it is
[quota.default] TOTAL, for CI time it is[quota.ci.default] TOTAL, and download traffic has no fallback, so it is unlimited.
In Forgejo, putting an owner in a group with no matching rule refuses everything. In Arbinel that only holds within a unit, so you can add a CI or traffic group to owners without breaking their storage.
Add-ons and grants raise existing rules
Section titled “Add-ons and grants raise existing rules”Add-ons and quota grants never create a limit. They add an amount to each of the owner’s rules that names one of their subjects exactly.
- A grant on
size:git:lfsdoes not raise a rule onsize:all, even though LFS counts towards it. - An owner in no group has no rule to raise.
The
[quota.default] TOTALand[quota.ci.default] TOTALfallbacks are never raised.
Write your group rules with the subjects you plan to sell or grant.
Storage warnings
Section titled “Storage warnings”Arbinel mails an owner when their storage reaches a share of a byte-counted rule.
A nightly cron task, quota_storage_notify, compares each owner’s stored bytes with their rules, add-ons included.
The mail goes to the user, or to every member of an organization’s Owners team.
It is sent regardless of the recipient’s mail preferences, because it describes account state, not activity.
| Key | Default | Meaning |
|---|---|---|
NOTIFY_THRESHOLDS |
80,100 |
Percentages of a rule at which the owner is mailed. Each is sent once per rule. An owner who crosses several at once is mailed only about the highest. An empty value turns the mails off. Entries outside 1 to 100 are dropped with an error in the log. |
NOTIFY_HYSTERESIS |
5 |
How many percentage points usage must fall below a threshold before that threshold can be sent again. 0 to 99. |
The mails need [quota] ENABLED and a working mailer.
Change the schedule in [cron.quota_storage_notify], as for any Forgejo cron task.
Quota pages for owners
Section titled “Quota pages for owners”Owners see their limits on the Storage overview settings page, which Arbinel extends with download traffic, and on the CI/CD usage page. Usage and add-ons describes both from the owner’s side.