---
title: Limits
path: limits
status: published
---

# Limits

The caps worth knowing before you design around them.

## Naming

| | |
|---|---|
| Bucket name | 3–63 characters, lowercase letters, digits, hyphens. **No dots.** |
| Object key | Standard S3 rules; any UTF-8, including spaces |

Dots are excluded from bucket names because they break TLS certificate matching
for virtual-host-style addressing — a bucket you could create but not reach over
HTTPS is worse than a name that is refused up front.

## Objects

| | |
|---|---|
| Object size | Use multipart upload above ~100 MB |
| Batch delete | 1000 keys per request |
| Listing page | 1000 keys per request, cursor-paginated |
| Multipart parts | Presigned 100 at a time |

Multipart parts are presigned in batches rather than all at once: a 10,000-part
upload would otherwise return megabytes of credentials, most of which expire
unused.

## Links

| Link type | Maximum lifetime |
|---|---|
| Presigned URL, `tenant.viewer` | 15 minutes |
| Presigned URL, `tenant.operator` and above | 1 hour |
| Share link | 7 days |

The cap is by role because a presigned URL outlives the session that made it. A
viewer who could mint week-long links would effectively hold permanent read
access.

**Revoking shares is all-or-nothing per bucket.** Revocation works by rotating
the signing key behind the links, which invalidates every outstanding link for
that bucket at once. An individual signature cannot be withdrawn — no service
can do that, and offering a per-link revoke button would be a promise that could
not be kept.

## Copying

Server-side copy works **within one region**. Copying between regions is not
offered as a single operation, because it moves data across a residency
boundary; download and re-upload if you want it, so the decision is explicit.

## Incomplete multipart uploads

An abandoned multipart upload keeps its parts, and those parts occupy real
capacity — so **they are billed as storage**. The console shows the count on
each bucket. Clean them up with your S3 client's abort-multipart operation.

We would rather show you this number than quietly bill for something invisible.

## Metering

| Meter | Billed |
|---|---|
| Storage (byte-hours) | ✅ |
| Egress | ✅ |
| Ingress | reported, not billed |
| Requests | reported, not billed |

Storage is sampled hourly. The console shows an `as of` timestamp with every
figure rather than implying it is live, and an hour that had to be estimated
after a collection gap is marked **estimated** rather than presented as
measured.

Storage continues to be metered while a tenant is suspended or read-only: the
data still occupies capacity. Only deletion stops storage billing.
