Product Docs Pricing Changelog
Start free Sign in
Docs / Guides / Limits & semantics

Limits & semantics

Flarelink adds almost no limits of its own — your backend runs on Cloudflare, so it inherits Cloudflare's. The few behaviours worth knowing up front are below. Cloudflare's numbers change over time; always confirm against their docs for anything you're designing around.

Inherited Cloudflare limits

Thing Limit (verify on CF docs) Notes
D1 database sizeup to ~10 GB per databasePer-database, not per-account. Plan a sharding/archival strategy well before you approach it.
D1 query resultbounded response sizePaginate large reads with .limit() / .offset(); don't SELECT * a huge table in one go.
Workers CPU time~10 ms (free) / much higher (paid)Your auth Worker is light, but heavy per-request work (e.g. high-iteration password hashing) needs the paid plan — see hashing.
R2 single-PUT objectup to ~5 GB (single request)Larger files need multipart upload (not yet wrapped in the SDK). No egress fees on R2.
KV value sizeup to ~25 MB per valueSessions are tiny; not a concern in practice.

Authoritative source: Cloudflare's D1, Workers, R2, and KV limits pages.

KV eventual consistency & sign-out

Sessions live in KV (see Architecture). KV is eventually consistent across Cloudflare's edge — a write (or delete) propagates globally over a short window rather than instantly everywhere.

The practical implication: when a user signs out, the session is deleted from KV, but a request hitting a far edge that hasn't seen the delete yet could still validate that session for a brief period (typically up to a minute). For the vast majority of apps this is a non-issue — but if you're building something where instant global revocation matters (e.g. killing a session after a security event), don't assume sign-out is synchronous everywhere. The same window applies to brand-new sessions just after sign-in.

Presigned URL expiry

  • expiresIn on createSignedUploadUrl / createSignedDownloadUrl is clamped to [60, 3600] seconds. The default is 300s. Values outside the range are clamped, not rejected.
  • Mint the URL right before you use it. A download URL embedded in a long-lived page will 403 once it expires — re-mint on demand from your server.
  • Rotating R2 credentials invalidates in-flight presigned URLs signed with the old keys — see Rotating R2 credentials.

Storage list pagination

storage.from(bucket).list({ prefix }) returns at most 1000 objects per call (R2's ListObjectsV2 page size). When there's more, the response carries a nextCursor — pass it back in to fetch the next page:

let cursor: string | undefined do { const { objects, nextCursor } = await flarelink.storage .from("uploads") .list({ prefix: "avatars/", cursor }) // …process objects… cursor = nextCursor } while (cursor)

The database builder has no implicit row cap, but bounded D1 response sizes mean you should always paginate large reads with .limit() + .offset() rather than pulling an entire table at once.

Something unclear or missing? hello@flarelink.dev llms-full.txt ↗