The Role of Durable Objects in OpenSEO: Architecture and Implementation

OpenSEO uses Cloudflare Durable Objects as isolated, SQLite-backed stateful compute primitives to power real-time SEO audits and AI chat sessions, eliminating the need for external databases for transient workflow data.

OpenSEO is an open-source SEO platform built on Cloudflare's edge infrastructure. According to the source code in the every-app/open-seo repository, Durable Objects in OpenSEO serve as the primary mechanism for maintaining state across distributed crawling operations and conversational AI workflows. The system defines three distinct Durable Object classes in wrangler.jsonc (lines 34-58), each optimized for specific persistent compute tasks.

The Three Durable Object Classes in OpenSEO

The wrangler.jsonc configuration binds three separate Durable Object classes to the worker runtime, each responsible for a distinct domain of stateful operations.

OnboardingChatAgent (ONBOARDING_CHAT)

The OnboardingChatAgent class handles project onboarding strategy chats. Each project receives its own isolated instance that persists chat history in an attached SQLite store. This ensures that onboarding conversations remain available across multiple HTTP requests without requiring a centralized chat database.

SamChatAgent (SAM_CHAT)

Implemented in src/server/features/sam/SamChatAgent.ts, this class powers the "SAM" in-app AI assistant. The system creates one instance per chat session, using the session ID as the unique instance identifier. As shown in lines 73-80, the worker authorizes access to the Durable Object before any RPC method executes, guaranteeing that only the session owner can retrieve or modify conversation history. The SQLite-backed storage enables fast retrieval of chat context for AI-driven tooling.

AuditScratchpad (AUDIT_SCRATCHPAD)

Defined in src/server/features/audit/AuditScratchpad.ts, this class functions as a per-audit crawl scratchpad. It maintains the frontier queue, link-edge graph, and slim page mirrors in a local SQLite database. The constructor (lines 10-14) establishes a cleanup alarm that automatically drops tables after 7 days if an audit never finalizes, preventing orphaned state from consuming storage resources. During active crawls, the scratchpad enables atomic operations where each chunk is claimed, processed, and stored without race conditions (lines 16-19).

How Durable Objects Work in OpenSEO

The platform leverages specific architectural patterns to maximize the reliability and performance of its edge-state layer.

Stateful Isolation at the Edge

Each Durable Object instance runs in its own isolated JavaScript environment with exclusive access to an attached SQLite database. This design provides durability across requests without requiring network calls to external databases. The SQLite storage is physically co-located with the compute instance, ensuring sub-millisecond access latency for crawl state and chat history.

Per-Instance Naming and Security

OpenSEO implements a security model based on deterministic instance naming. The worker generates Durable Object IDs using client-provided identifiers—the audit ID for AUDIT_SCRATCHPAD or the session ID for SAM_CHAT—via the idFromName() method. Before invoking any RPC, the worker validates that the requesting user owns the specified instance name. This guarantees that only authorized clients can read or write the isolated SQLite state associated with their specific workflow.

Atomic RPC Execution

All methods executing inside a Durable Object run synchronously because SQLite operations within a DO are synchronous. Consequently, each RPC call represents an atomic transaction. This atomicity underpins the crawl-loop logic, allowing idempotent writes and safe retries. If a worker retry occurs, the AuditScratchpad maintains consistency because the partial state from the failed attempt never commits halfway; it either completes entirely or rolls back within the same RPC boundary.

Automatic Lifecycle Management

The AuditScratchpad implements self-destructing state. Upon construction, it schedules an alarm that triggers after 7 days of inactivity. If the audit workflow never reaches completion, the alarm handler drops all SQLite tables associated with that audit ID. This automatic cleanup prevents storage costs from accumulating for abandoned crawl jobs without requiring external cron jobs or garbage collection services.

Working with Durable Objects: Code Examples

The following patterns demonstrate how OpenSEO interacts with its Durable Object bindings in production workflows.

Creating a per-audit scratchpad and initializing a crawl:

const auditScratchpad = env.AUDIT_SCRATCHPAD.get(
  env.AUDIT_SCRATCHPAD.idFromName(auditId)
);
await auditScratchpad.seedStart(startUrl);

Claiming a batch of URLs for distributed processing:

const { urls, isRetry } = await auditScratchpad.claimChunk(chunkNo, 50);

Recording crawl results back into the scratchpad:

await auditScratchpad.recordBatch({
  crawledUrls,
  pages,
  links,
  discovered,
});

Accessing the SAM chat agent from the worker:

const samChat = env.SAM_CHAT.get(env.SAM_CHAT.idFromName(sessionId));
await samChat.fetch(request); // attaches origin & handles the Think agent

Summary

  • Three specialized classesOnboardingChatAgent, SamChatAgent, and AuditScratchpad—handle distinct stateful workflows in OpenSEO.
  • SQLite-backed persistence provides durable, low-latency storage directly at the edge without external database dependencies.
  • Atomic RPC operations ensure data consistency during concurrent crawl processing and enable safe retry semantics.
  • Automatic cleanup alarms prevent resource leaks by deleting orphaned audit data after 7 days of inactivity.
  • Per-instance authorization uses deterministic naming (session IDs, audit IDs) to enforce strict data isolation between users and projects.

Frequently Asked Questions

What is the primary role of Durable Objects in OpenSEO?

Durable Objects provide low-latency, edge-localized persistence for workflow-specific data such as SEO crawls and chat sessions. They store transient state in SQLite databases physically attached to each compute instance, allowing OpenSEO to maintain complex state across distributed workers without relying on external databases for temporary data.

How does OpenSEO ensure data isolation between different users?

Each Durable Object instance is named uniquely using project IDs, session IDs, or audit IDs via the idFromName() method. The worker validates ownership before routing requests to the DO, and the SQLite storage is physically isolated per instance. This architecture ensures that users cannot access scratchpads or chat histories belonging to other accounts.

What happens to audit data if a crawl never completes?

The AuditScratchpad class sets a cleanup alarm during construction that automatically deletes SQLite tables after 7 days if the audit workflow never finalizes. This self-healing mechanism prevents storage resource leaks from abandoned or failed crawl operations.

Why does OpenSEO use synchronous SQLite operations inside Durable Objects?

Synchronous SQLite execution within a Durable Object ensures that each RPC call executes as an atomic transaction. This eliminates race conditions during multi-step crawl operations and allows the system to safely retry failed chunks without risking data corruption or partial state commits.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →