The appliance assigns each organization a named usage tier and keeps quota policy separate from identity and deployment orchestration. New organizations start on Free and may move themselves between Free and Standard. Enterprise requires a platform operator. The bootstrap Local Development organization starts on Standard so the curated examples fit without special overrides. Organization members can inspect current usage in Usage & limits. Platform operators can open http://admin.ermahgerd.localhost:8082 and select Platform → Organizations to set or reset an override and review quota-change and rejection history.

What is enforced
The control plane reserves organization capacity before creating a Worker or queue. Those reservations are atomic in the quota service, so two concurrent requests cannot both consume the final available slot. Failed creates release their reservation. Listing those resources reconciles the authoritative count, which repairs accounting after an interrupted operation.
Storage, queue backlog, and key-value holdings are accounted for by the services that own the durable state:
- R2 checks the current organization bucket and retained-byte limits before committing growth in its organization-scoped catalog. The appliance-wide storage safety ceiling remains an upper bound even if an organization override is higher.
- Queues reserve the exact UTF-8 byte size of accepted message bodies before committing them. Delivery, expiry, dead-letter transfer, purge, and deletion release the corresponding bytes.
- The key-value service reserves namespace, live-key, and stored-value deltas before its Durable Object transaction. Replacement writes reserve only their byte delta, while deletes and TTL expiry return capacity.
Each provider publishes absolute snapshots when its durable state is first opened. Delta reservations then keep the centralized view current. A failed growth check fails closed; cleanup remains possible and causes a later authoritative reconciliation if a decrement could not be recorded immediately.
The native Durable Objects shard manager applies the same pattern to namespace holdings before a migration can add classes. Free, Standard, and Enterprise start at 3, 20, and 100 namespaces respectively. Native object count and SQLite bytes are observed for operations and tenant visibility; they are not currently presented as hard storage entitlements.
Reducing a limit below current usage does not delete tenant data. The resource is shown as over quota and further growth is rejected until usage falls below the allowance or a platform operator raises it. Deletes remain available.
Monthly usage is metered and enforced at each trusted provider boundary. Every runtime dispatch counts as one Worker invocation, including HTTP requests, service-binding calls, queue batches, and other event handlers supported by the runtime. Each authenticated R2 request counts as one R2 operation. Queue batches count each accepted message as one operation, while each key-value get, put, delete, or list counts as one key-value operation. Stable event identifiers make provider retries idempotent in the quota ledger. Each accepted native image transformation counts as one Images operation. Each accepted model call counts as one inference, independent of the provider’s own token accounting. Vector insert, upsert, read, search, and delete calls are metered at the vector-service boundary; index and stored-vector holdings are reconciled from its durable catalog.
The provider reserves a period operation before performing it and fails closed if the quota service is unavailable or the monthly allowance would be exceeded. Period meters therefore begin each calendar month at a known zero; Not reporting is reserved for a holding provider that has not yet published its authoritative snapshot. Worker counts, R2 buckets and retained bytes, queue counts and backlog bytes, and all key-value holding dimensions remain authoritative as well.
The shared runtime’s CPU and memory are available as capacity telemetry, but the
standalone workerd server does not currently provide usable per-Worker CPU or
memory accounting. Neither is included in tenant usage. A future CPU quota must
start with an authoritative attribution and enforcement boundary; request or
event counts are not treated as interchangeable stand-ins for compute cost.
Tier allowances
| Resource | Free | Standard | Enterprise |
|---|---|---|---|
| Workers | 10 | 100 | 250 |
| Durable Object namespaces | 3 | 20 | 100 |
| Databases | 3 | 10 | 25 |
| Database storage | 128 MiB | 1 GiB | 4 GiB |
| Static assets | 64 MiB | 512 MiB | 2 GiB |
| R2 buckets | 3 | 10 | 25 |
| R2 retained bytes | 512 MiB | 2 GiB | 8 GiB |
| Queues | 3 | 10 | 25 |
| Queue backlog bytes | 8 MiB | 64 MiB | 256 MiB |
| Key-value namespaces | 3 | 10 | 25 |
| Key-value keys | 1,000 | 10,000 | 50,000 |
| Key-value stored bytes | 8 MiB | 64 MiB | 256 MiB |
| Image transformations / month | 1,000 | 25,000 | 100,000 |
| Inference providers | 1 | 3 | 3 |
| Model inferences / month | 1,000 | 25,000 | 250,000 |
| Vector indexes | 1 | 5 | 20 |
| Stored vectors | 2,000 | 20,000 | 100,000 |
| Vector operations / month | 20,000 | 250,000 | 2,000,000 |
Most established period meters currently retain the same policy ceilings across tiers: 50 million Worker invocations and 10 million operations per established data primitive per calendar month. Images, Models, and Vector search use the tier-specific allowances shown above.
Defaults are product policy in quotas/src/ermahgerd_quotas/domain.py.
Organization overrides are stored in the quota service’s SQLite database at
/var/lib/ermahgerd-quotas/quotas.sqlite3.
Changing your tier
Organization owners can change between Free and Standard in the tenant console: open Usage & limits, choose Change tier, review the allowances, and confirm. The review includes support overrides and highlights allowances below current usage. Changes take effect immediately; there is currently no charge. Enterprise is reserved and is not offered as a selectable tier.
No reason is required. Change history automatically records the owner, previous tier, new tier, and time. Other organization roles can see the current tier but cannot change it. API tokens and platform administrator sessions cannot change tiers either; an administrator who also owns an organization must use their tenant session.
Changing tiers preserves support overrides and existing resources. After a downgrade, growth beyond an allowance is blocked until usage is reduced; period usage resets at the start of its next accounting window.
Administration
Platform viewers can inspect allowances, usage, change history, and enforcement events. The organization’s tier is read-only in administration. Platform operators can set individual quota overrides or reset an override to the organization’s tier allowance. The audit history records the operator, old and new values, and time without requiring a free-form reason. These actions do not change the owner’s selected tier. There is no administrative tier-change API.
Quota changes do not involve prices, invoices, payment state, or plans. The service deliberately records quantities and policy only, leaving future billing or cost attribution as a separate concern.
Service boundary
The quota API listens on the control node’s private WireGuard address and has two distinct surfaces:
- authenticated tenant and platform reads/administration, authorized through the identity service;
- a service-token-protected internal API for absolute usage snapshots, atomic reservations, and idempotent period-meter events.
Prometheus scrapes /metrics, while Alloy collects its systemd journal. The
control plane treats quota readiness as a required dependency because silently
allowing growth when enforcement is unavailable would invalidate configured
limits.