Skip to content

Costs and limits

Cirrus is built to be cheap to run for a single account. Most personal PDS deployments fit inside Cloudflare’s free tier. This page covers the cost model and the limits that matter.

Three Cloudflare products, each priced separately:

  • Workers — request count, CPU time per request.
  • Durable Objects — request count, wall-clock duration, storage (SQLite-backed).
  • R2 — storage (per GB-month), Class A operations (writes), Class B operations (reads), no egress fees.

Refer to Cloudflare’s current pricing for exact numbers; this page does not quote prices that can change.

For an active single-user account on the Bluesky network, expect:

  • Worker requests: hundreds to low thousands per day, mostly firehose subscribers polling and the Bluesky app’s reads.
  • Durable Object requests: every write, every firehose broadcast. Lower than the Worker count.
  • Durable Object storage: under 100 MB for the repository in most cases.
  • R2 storage: dominated by blobs. A few hundred MB for an account with many image posts.
  • R2 operations: one Class A per blob upload, one Class B per blob fetch.

The free tier of Workers covers up to 100,000 requests per day, which is well above what a personal PDS uses for its own traffic. R2 has a generous free tier for storage and operations.

  • A popular post. A large number of clients fetching the same blob increases Class B operations.
  • A firehose subscriber that reconnects often. Each reconnect replays from a cursor and re-broadcasts events. Well-behaved relays do not do this.
  • Many large blobs. Video, in particular, increases R2 storage.

Cirrus does not implement any rate limiting beyond what Cloudflare provides. For unusual traffic, the Cloudflare dashboard’s analytics show what is consuming requests.

These are limits set by Cirrus or by the platform that cannot be raised without code changes:

LimitValueSource
Blob upload size60 MBCirrus
Single Worker request CPU30 s (paid) / 10 ms (free)Cloudflare Workers
Durable Object SQLite size10 GBCloudflare Durable Objects
Single record size~1 MB practicalAT Protocol + lexicon
WebSocket message size1 MBCloudflare Workers
Concurrent WebSocket connections per DOthousands (no hard limit)Cloudflare Durable Objects

The 60 MB blob limit is hardcoded in uploadBlob. That covers full-resolution photos and short videos. Anything larger — long-form video, raw camera files — has to be split, hosted externally, or compressed before upload.

The 10 GB SQLite limit is the ceiling for the repository size. For context, the repository is the metadata — record values, MST nodes, commit log. Blobs are not counted. A heavily-used personal account is in the low hundreds of MB.

  • Single Durable Object means single region. Latency from the other side of the world is real. The repository write path is fast but not edge-local.
  • Worker CPU time for big operations like CAR exports of a large repository can approach the per-request budget. The getRepo endpoint streams to keep memory low, but a very large repository can still be slow to serve.
  • Firehose broadcast fan-out is O(connected clients). For a personal PDS, this is in the low tens (one or two relays, maybe a personal subscriber). For a popular relay subscribing, it is one client receiving every event.

The Cloudflare dashboard breaks costs down by product. For a Cirrus deploy, look at:

  • Workers & Pages → Analytics & Logs for request counts and CPU time.
  • Workers & Pages → Durable Objects → namespace for DO request counts and storage.
  • R2 → bucket → Metrics for storage and operation counts.

For most personal accounts, the bill is dominated by R2 storage once it exceeds the free tier, which only happens with a meaningful amount of media.