Durable Objects pricing

How are Cloudflare Durable Objects billed?

Cloudflare Durable Objects are billed along two dimensions: compute and storage. On the Workers Paid plan, compute costs $0.15 per million requests and $12.50 per million GB-seconds of duration beyond included quotas, while the Free plan provides daily allocations of 100,000 requests and 13,000 GB-seconds.

If you don't design your state lifecycle carefully, compute duration can dominate your monthly bill. Inactive objects receiving no requests don't incur any duration charges, but an object held active in memory charges for wall-clock time continuously, even if it's doing nothing between events.

Compute requests: HTTP, RPC, alarms, and WebSockets

Every incoming interaction with a Durable Object counts toward compute request billing. This includes direct HTTP requests, RPC sessions, alarm invocations, and incoming WebSocket messages.

Each RPC method call made on a Durable Object stub counts as a single billed request because Cloudflare treats every stub invocation as its own RPC session. But there is an exception worth knowing: when an RPC method call returns an object extending RpcTarget, subsequent calls on that returned stub stay inside that same RPC session and don't count as extra billed requests. If you batch work through returned targets, you can cut stub request counts down fast.

WebSockets have specific accounting rules for requests:

  • Establishing the connection requires a billed request.
  • Outgoing WebSocket messages sent from the object are free.
  • Incoming WebSocket protocol pings are free.
  • Incoming WebSocket messages get a 20:1 discount. Cloudflare charges 100 incoming WebSocket messages as 5 billable requests.

That 20:1 ratio is strictly for request billing. It doesn't alter your Durable Object metrics or analytics dashboards, which continue to report raw message counts.

Duration billing and the 128 MB memory floor

Cloudflare measures compute duration in wall-clock time while the Durable Object is actively executing or sitting idle in memory unable to hibernate. Inactive objects receiving zero traffic cost nothing for duration.

The billing engine always calculates duration using a fixed 128 MB memory allocation per active instance. It doesn't matter if your JavaScript code only uses 8 MB of heap, or if Cloudflare packs multiple instances of your class into the same isolate on a physical host to share resources; you are still billed as if that object consumes a dedicated 128 MB. Duration is shared across all concurrent requests active on a single object at the same time, so twenty simultaneous callers inside the same second run on that single second of billable duration.

What keeps an object stuck in memory? Any pending I/O operation keeps a Durable Object awake for up to 15 minutes, charging you wall-clock time the whole way through.

On the Paid plan, excess billable usage rounds up to the next billable unit before Cloudflare applies the rate. If you consume 500,000 GB-seconds of billable compute duration over your quota, Cloudflare rounds your usage up to 1,000,000 GB-seconds on your bill. That round-up makes long-running background tasks noticeably expensive if you aren't hibernating your sockets.

Cutting duration to zero with WebSocket hibernation

Are Durable Objects billed while idle? If you call the standard accept() method on a WebSocket, yes. Calling standard accept() keeps the object active in memory, running up duration charges for the entire life of the WebSocket connection.

To stop paying duration while clients stay connected, you must use the WebSocket Hibernation API. When an object hibernates, Cloudflare evicts the instance from memory while holding the client's TCP and TLS connection open at the edge network. Billable GB-second duration stops accruing the instant the object is idle and eligible for hibernation, even before the runtime actually tears down the isolate.

export default {
  async fetch(request, env) {
    const id = env.MY_DO.idFromName("room-1");
    const stub = env.MY_DO.get(id);
    return stub.fetch(request);
  }
};

export class ChatRoom {
  constructor(ctx, env) {
    this.ctx = ctx;
  }

  async fetch(request) {
    const pair = new WebSocketPair();
    const [client, server] = Object.values(pair);

    // Allows hibernation; standard server.accept() does not
    this.ctx.acceptWebSocket(server);

    return new Response(null, { status: 101, webSocket: client });
  }

  async webSocketMessage(ws, message) {
    ws.send(`Echo: ${message}`);
  }
}

When an incoming message or alarm hits a hibernated object, the runtime re-initializes it, runs its constructor, and executes the event handler. Because the in-memory state resets on wake-up, you can't rely on global class variables to store connection data. You can persist per-connection metadata using WebSocket.serializeAttachment(value) and WebSocket.deserializeAttachment(), which accept any structured-cloneable value up to 16,384 bytes.

Cloudflare's runtime also answers protocol ping frames automatically with pong responses. These heartbeats don't wake the object or invoke webSocketMessage, so they don't break hibernation. Similarly, auto-responses configured with state.setWebSocketAutoResponse() execute without adding wall-clock time or duration charges.

Storage backends: SQLite vs key-value

Durable Objects support two storage engines: SQLite and legacy key-value. Cloudflare recommends SQLite for all new projects.

MetricFree Plan (SQLite)Paid Plan (SQLite)Paid Plan (Key-Value)
Compute Requests100,000 / day1M / month, then $0.15 / M1M / month, then $0.15 / M
Compute Duration13,000 GB-s / day400,000 GB-s / month, then $12.50 / M400,000 GB-s / month, then $12.50 / M
Stored Data5 GB total5 GB-month, then $0.20 / GB-month1 GB-month, then $0.20 / GB-month
Reads5M row reads / day25B rows / month, then $0.001 / M1M read units, then $0.20 / M (4 KB/unit)
Writes100,000 row writes / day50M rows / month, then $1.00 / M1M write units, then $1.00 / M (4 KB/unit)
DeletesCounted as row writes$1.00 / M rows written1M delete units, then $1.00 / M (unmetered)

SQLite backend

Free plan accounts can only create and access SQLite-backed Durable Objects. The read and write quotas mirror Cloudflare D1 pricing.

If you call legacy key-value storage methods (get(), put(), delete(), list()) on a SQLite-backed object, those operations target a hidden SQLite table and get billed as standard row reads and writes. Furthermore, each setAlarm() call writes a row, and deletes count directly as rows written.

An empty SQLite database starts at roughly 12 KB of billable storage, and empty tables add a few kilobytes depending on how wide the columns are. Every write appends nominal metadata into internal tracking tables, which continues counting toward your storage balance until you issue a deleteAll() call.

Key-value backend

The key-value backend is restricted to the Workers Paid plan. Read and write units are calculated in 4 KB chunks. If you write a 9 KB value, that single operation uses 3 write request units.

List operations bill based on the total bytes examined across keys and values. A list request evaluating 80 KB of records costs 20 read request units; if a list scan finds nothing, it still bills a minimum of 1 read unit. Reading from the local memory cache or executing multi-key lookups doesn't give you a discount; Cloudflare bills cached and multi-key operations at the normal per-key request unit rates.

Free plan rules and limits

Are Durable Objects available on the free plan? Yes, but with strict guards. The Free plan includes daily quotas that reset every day at 00:00 UTC.

If your application exceeds any single free tier limit during that 24-hour window, further operations of that type fail with an error immediately. There's no automatic overage billing on the Free plan. To keep your application running during traffic bursts, you have to upgrade to the Workers Paid plan, which requires a minimum $5 monthly usage fee. Note that pricing examples in the docs exclude the cost of the caller Worker, which is metered separately under standard Cloudflare Workers pricing.

Monitoring Durable Objects spend with Costbrake

If you have a WebSocket connection that forgets to hibernate, or an alarm loop running every few seconds, duration and request costs can creep up quickly.

Costbrake watches what you spend across 23 cloud, AI and SaaS providers, including Cloudflare, AWS and Google Cloud. It pulls Cloudflare usage metrics priced at list rates and pulls final billed dollars about a day later. If an unhibernated Durable Object spikes your usage, Costbrake detects hours that cost more than 3x your 7-day baseline (with at least a $5 increase) and notifies you via email, Slack, Discord, webhooks or PagerDuty.

On Pro ($12/month) and Team ($39/month), you also get opt-in, reversible brakes that run when an admin clicks and confirms. If compute runs wild, an admin can click to detach custom domains, pause cron triggers, roll back deployments, or block Workers and Durable Objects usage with a Cloudflare spend policy. For details on how Cloudflare policies cap runaway usage, see our walkthrough on whether you can put a spending limit on Cloudflare Workers, Durable Objects and R2.

You can connect your workspace in minutes by telling your AI coding agent to follow the instructions at agent setup.

Questions and answers

Are Durable Objects billed while idle?

Inactive Durable Objects that receive no requests do not incur any duration charges. However, if an object stays loaded in memory and cannot hibernate (for instance, holding a socket with standard accept()), it is billed continuously for its 128 MB memory allocation in wall-clock time.

How does WebSocket hibernation reduce cost?

The WebSocket Hibernation API lets Cloudflare evict the Durable Object from memory while keeping client connections open on the edge network. Because the instance is no longer in memory, billable duration charges stop completely until a new message arrives.

Are Durable Objects available on the Workers Free plan?

Yes, Durable Objects are available on the Free plan, but you can only create and access SQLite-backed objects. The Free plan includes 100,000 requests, 13,000 GB-seconds, 5 million row reads, 100,000 rows written per day, and 5 GB total storage, resetting daily at 00:00 UTC.

How does rounding work on Paid plan duration?

Billable compute duration in excess of the monthly 400,000 GB-second allocation is rounded up to the next billable unit before rates apply. For instance, consuming 500,000 GB-seconds of billable overage rounds up to 1,000,000 GB-seconds and is billed at $12.50.

How are incoming WebSocket messages billed for requests?

Incoming WebSocket messages are billed at a 20:1 ratio for compute requests, meaning 100 incoming messages count as 5 billed requests. Outgoing messages and incoming protocol pings are free, while establishing the connection counts as one request.

Sources

Updated