Cloudflare Agents and Durable Objects: A First Look

Cloudflare offers several options for building applications on its edge network. Two key technologies are Durable Objects and the newer Cloudflare Agents. Both are serverless compute options designed for creating scalable applications with low latency. They both leverage Cloudflare’s global network, bringing compute closer to your users.

At their core, both technologies deal with statefulnessβ€”the ability to maintain data across requestsβ€”and edge computing, which means processing data closer to the user. However, Agents represent an evolution, building upon the foundation laid by Durable Objects and adding several significant features. Think of Agents as Durable Objects, but with a lot more built-in capability.

Cloudflare Durable Objects vs Agents: A visual comparison for choosing the right tool.

Durable Objects: The Foundation of Stateful Edge Computing

Durable Objects are Cloudflare’s original building blocks for stateful applications. They provide a way to manage data and coordinate interactions between multiple clients globally. A central concept is the globally unique ID, generated using `idFromName()`. This function ensures that only one instance of a Durable Object exists for a given name, which is essential for consistent state management.

Each Durable Object has attached durable storage. You can choose between SQLite for smaller datasets or a key-value store for larger needs. This persistence is what allows them to maintain state across requests. Durable Objects excel in scenarios like leaderboards, shopping carts, or collaborative applications where consistent state is paramount. They’re ideal when you need a single source of truth accessible from anywhere in the world.

However, Durable Objects aren’t a silver bullet. They aren’t designed for long-running processes, and managing complex workflows can become cumbersome. While they can handle some level of concurrency, they aren’t optimized for handling a massive number of simultaneous connections. This is where Cloudflare Agents come into play.

Cloudflare Agents: Durable Objects, But More

Cloudflare Agents can be seen as an evolution of Durable Objects, offering all the core functionality while adding significant enhancements. They’re designed to address some of the limitations of Durable Objects and provide a more comprehensive platform for building complex applications.

The key additions are built-in WebSocket support, hibernation capabilities, and "mini-workflows". The WebSocket support is particularly important, as it simplifies the development of real-time applications. Hibernation allows Agents to automatically pause and resume execution, reducing costs for intermittent workloads. Mini-workflows provide a way to orchestrate tasks without the need for a separate orchestration service.

WebSocket Workloads: Why Agents Have an Edge

Durable Objects can technically handle WebSocket connections, but it’s not their strong suit. Maintaining persistent connections with Durable Objects often involves complex polling mechanisms and careful management of state. This can be resource-intensive and lead to higher latency.

Cloudflare Agents, with their built-in WebSocket support, dramatically simplify this process. They handle the complexities of connection management internally, allowing you to focus on the application logic. Imagine building a real-time chat application or a collaborative document editor – Agents are specifically designed to make these kinds of applications easier to develop and more performant. The reduced overhead translates to lower latency and a better user experience.

WebSocket Implementation: Durable Objects vs Cloudflare Agents

This comparison demonstrates the architectural differences between implementing WebSocket connections using Durable Objects versus Cloudflare Agents. The Durable Objects approach requires manual session management, state handling, and WebSocket lifecycle management, while Agents provide a more abstracted, simplified interface.

// DURABLE OBJECTS APPROACH - More Complex Setup
// worker.js
export default {
  async fetch(request, env) {
    if (request.headers.get('Upgrade') !== 'websocket') {
      return new Response('Expected websocket', { status: 400 });
    }

    const id = env.WEBSOCKET_DURABLE_OBJECT.idFromName('websocket-session');
    const stub = env.WEBSOCKET_DURABLE_OBJECT.get(id);
    return stub.fetch(request);
  }
};

// websocket-durable-object.js
export class WebSocketDurableObject {
  constructor(state, env) {
    this.state = state;
    this.sessions = new Map();
  }

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

    await this.handleSession(server);
    
    return new Response(null, {
      status: 101,
      webSocket: client,
    });
  }

  async handleSession(webSocket) {
    webSocket.accept();
    const sessionId = crypto.randomUUID();
    this.sessions.set(sessionId, webSocket);

    webSocket.addEventListener('message', async (event) => {
      const message = JSON.parse(event.data);
      // Handle message logic
      await this.broadcastMessage(message, sessionId);
    });

    webSocket.addEventListener('close', () => {
      this.sessions.delete(sessionId);
    });
  }

  async broadcastMessage(message, excludeSession) {
    for (const [sessionId, ws] of this.sessions) {
      if (sessionId !== excludeSession && ws.readyState === 1) {
        ws.send(JSON.stringify(message));
      }
    }
  }
}

// CLOUDFLARE AGENTS APPROACH - Simplified
// agent-websocket.js
export default {
  async fetch(request, env) {
    const agent = new env.WEBSOCKET_AGENT();
    
    // Simplified WebSocket handling with built-in state management
    return agent.handleWebSocket(request, {
      onMessage: async (message, session) => {
        // Automatic message broadcasting and session management
        await session.broadcast(message);
      },
      onConnect: (session) => {
        console.log('Client connected:', session.id);
      },
      onDisconnect: (session) => {
        console.log('Client disconnected:', session.id);
      }
    });
  }
};

The Durable Objects implementation requires approximately 50+ lines of code with manual session tracking, WebSocket pair creation, and event handling. In contrast, the Cloudflare Agents approach reduces this to under 20 lines by abstracting away the complexity of state management and providing built-in methods for common WebSocket operations like broadcasting and session handling. Choose Durable Objects when you need fine-grained control over state and custom logic, and Agents when you want rapid development with standard WebSocket patterns.

Managing Long-Running Tasks: Hibernation and Mini-Workflows

Serverless environments present unique challenges when it comes to long-running tasks. Traditionally, you’d need to break down these tasks into smaller chunks or rely on external orchestration services. Cloudflare Agents address this with their hibernation feature. Hibernation automatically pauses execution when an Agent is idle, reducing compute costs significantly.

Furthermore, the mini-workflows functionality allows you to orchestrate complex tasks within the Agent itself, without needing a separate service like Cloudflare Workers Orchestrate. This is useful for tasks like image processing, data transformation, or any process that involves multiple steps. It streamlines the development process and reduces operational complexity.

Cost Considerations: Durable Objects vs. Agents

The pricing models for Durable Objects and Cloudflare Agents differ. Durable Objects are billed based on storage used (SQLite or key-value) and compute time. Agents also factor in WebSocket connection duration and the usage of mini-workflows. It’s not always straightforward to say which is cheaper.

Hibernation in Agents can lead to substantial cost savings for intermittent workloads. If your application has periods of inactivity, the automatic pausing and resuming of Agents can significantly reduce your compute bill. However, for consistently active applications, the additional features of Agents might result in a slightly higher cost. Careful consideration of your workload patterns is essential.

  • Durable Objects: Storage (SQLite/Key-Value), Compute Time
  • Cloudflare Agents: Storage, Compute Time, WebSocket Duration, Mini-Workflow Usage

Cost Comparison: Chat Application (100 Concurrent Users)

FeatureDurable ObjectsCloudflare AgentsNotes
Monthly Storage (10GB)$2.50$3.00Based on Cloudflare's storage pricing as of November 2023. Durable Objects use a slightly cheaper storage tier.
Compute (Requests - 1 Million)$8.00$12.00Calculated at $8/million requests for Durable Objects and $12/million for Agents (November 2023 pricing). Agents have higher per-request cost.
Network Egress (100GB)$1.00$1.00Cloudflare's egress pricing is generally consistent for both. Assumes standard egress rates.
Estimated Total Monthly Cost$11.50$16.00Sum of storage, compute, and network costs. This is an estimate and can vary.
State Updates/Second (Average)50200Durable Objects are optimized for lower frequency, larger state updates. Agents handle higher frequency, smaller updates better.
Maximum Concurrent Connections100500Agents offer higher concurrency limits. Durable Objects may require scaling for higher loads.
Cold StartsMore FrequentLess FrequentDurable Objects can experience cold starts more readily, impacting initial response times. Agents are designed for faster warm-up.
ComplexityModerateLowerAgents generally require less boilerplate code for similar functionality.

Data sourced from AI research β€” verify before making decisions

Choosing the Right Tool: A Decision Guide

So, which should you choose? Durable Objects are a great fit for simple stateful applications that don’t require extensive real-time capabilities or long-running processes. If you need a basic way to manage data at the edge, Durable Objects are a solid choice.

Cloudflare Agents are the better option for complex applications, especially those that are WebSocket-heavy, involve long-running tasks, or require hibernation for cost optimization. They aren’t a replacement for Durable Objects, but rather an extension of the platform, offering a more powerful and versatile set of tools. Ultimately, the best choice depends on the specific requirements of your application.

  1. Choose Durable Objects if: You need simple stateful functionality with low WebSocket usage.
  2. Choose Cloudflare Agents if: Your application is complex, WebSocket-heavy, requires hibernation, or needs mini-workflows.

Cloudflare Agents vs. Durable Objects: Which is Right For You?

  • Does your application require maintaining state across requests and coordinating that state between multiple concurrent users?
  • Are you building a real-time application that heavily utilizes WebSockets for persistent connections?
  • Do your core tasks require execution times exceeding Cloudflare Workers' standard execution limits (e.g., >50ms)?
  • Is cost a primary concern, and are you optimizing for the lowest possible expense, even if it means more complex code?
  • Do you need to perform long-running background tasks that don't require immediate responses to the user?
  • Is your application's logic primarily stateless, focusing on request/response cycles without significant data persistence?
  • Do you require fine-grained control over the execution environment and access to a wider range of system resources?
Based on your selections, you should have a clearer understanding of whether Cloudflare Durable Objects or Cloudflare Agents are the more appropriate solution for your use case. Review your answers and consult the Cloudflare documentation for detailed implementation guidance.