# OpenSEO Architecture: A Deep Dive Into Its Core Components

> Explore the core components of OpenSEO architecture. Understand its eight modular layers including Workers runtime, Durable Objects, workflow orchestration, and more.

- Repository: [Every App/open-seo](https://github.com/every-app/open-seo)
- Tags: architecture
- Published: 2026-09-01

---

**OpenSEO is a Cloudflare-edge application built from eight modular layers: a Workers runtime engine, three Durable Object families for stateful workflows, a Workflow orchestration system, type-safe server functions, a dual-database abstraction, flexible authentication modes, self-hosting utilities, and a React-based front end.**

The every-app/open-seo repository implements a cloud-native SEO platform designed for scalability, low latency, and flexible deployment. Understanding its architecture is essential for contributors customizing the platform or teams evaluating it for production use.

## Cloudflare Workers Runtime

OpenSEO executes all server-side logic on Cloudflare's edge network. The entry point in [`src/server.ts`](https://github.com/every-app/open-seo/blob/main/src/server.ts) initializes the worker environment (`env`) and registers server functions.

This design eliminates cold starts and places compute geographically close to users. Every public endpoint routes through **TanStack React-Start server functions** created with `createServerFn`.

```typescript
// src/server.ts — worker bootstrap and server function registration
export default {
  async fetch(request, env, ctx) {
    // wires env and registers all server functions
  }
};

```

## Durable Objects: The State Layer

Three Durable Object (DO) families provide persistent, low-latency state for long-running operations. Unlike ephemeral Workers, DOs maintain memory across requests.

### AuditScratchpad

The `AuditScratchpad` DO holds crawl frontier state, link graphs, and page mirrors during site audits. It isolates heavy crawl data from the workflow runner, preventing memory exhaustion.

```typescript
// src/server/features/audit/AuditScratchpad.ts
export class AuditScratchpad extends DurableObject {
  constructor(ctx: DurableObjectState, workerEnv: Env) {
    super(ctx);
    // SQLite storage initialization
  }

  async leaseChunk(chunkSize: number): Promise<string[]> {
    // fetch pending URLs and mark as leased
  }
}

```

Namespaces are declared in [`src/env.d.ts`](https://github.com/every-app/open-seo/blob/main/src/env.d.ts):

```typescript
// src/env.d.ts
interface Env {
  AUDIT_SCRATCHPAD: DurableObjectNamespace<AuditScratchpad>;
  ONBOARDING_CHAT: DurableObjectNamespace<OnboardingChatAgent>;
  SAM_CHAT: DurableObjectNamespace<SamChatAgent>;
}

```

### OnboardingChatAgent and SamChatAgent

These DOs persist multi-turn conversations for the onboarding flow and the in-app SAM agent respectively. Each conversation maintains independent state without database round-trips.

## Workflow Orchestration

The `SiteAuditWorkflow` in [`src/server/workflows/SiteAuditWorkflow.ts`](https://github.com/every-app/open-seo/blob/main/src/server/workflows/SiteAuditWorkflow.ts) orchestrates multi-step crawls using Cloudflare Workflows. It leases work from the `AuditScratchpad` DO, executes chunks in parallel, and updates progress counters.

This architecture separates **memory** (the workflow runner) from **heavy state** (the DO), eliminating OOM errors and step-output limits.

```typescript
// src/server/workflows/SiteAuditWorkflow.ts
export default {
  async crawlChunk(step) {
    const scratchpad = env.AUDIT_SCRATCHPAD.get(step.auditId);
    const urls = await scratchpad.leaseChunk(200);
    const results = await fetchPages(urls);
    await scratchpad.savePages(results);
    return { crawled: results.length };
  },
};

```

The design is documented in [`specs/0009-site-audit-crawl-architecture.md`](https://github.com/every-app/open-seo/blob/main/specs/0009-site-audit-crawl-architecture.md).

## Server Functions (API Layer)

All business logic exposes thin, type-safe wrappers consumed by the front end. These live in `src/serverFunctions/` and cover domains including projects, keywords, Lighthouse audits, GA4/GSC integrations, rank tracking, and billing.

```typescript
// src/serverFunctions/workspace.ts
export const getWorkspaceMergeStatus = createServerFn({ method: "POST" })
  .middleware(requireAuthenticatedContext)
  .handler(async () => {
    if (!isCloudflareAccessMode()) {
      return { legacyWorkspaceCount: 0 };
    }
    return {
      legacyWorkspaceCount: await WorkspaceMergeService.countLegacyWorkspaces(),
    };
  });

```

## Database Abstraction with Drizzle

OpenSEO uses **Drizzle ORM** to generate schemas compatible with both **Cloudflare D1** (SQLite) and **PostgreSQL**. Product data—projects, audits, pages, backlinks—lives in these tables, while transient crawl data remains in Durable Objects.

```typescript
// src/db/schema.ts
export const projects = pgTable("projects", {
  id: serial("id").primaryKey(),
  name: text("name").notNull(),
  createdAt: timestamp("created_at").defaultNow(),
});

```

Generated migration files appear in `drizzle/` (SQLite) and `drizzle-pg/` (PostgreSQL).

## Authentication and Authorization

The auth stack supports three deployment modes:

- `cloudflare_access` — Cloudflare Access for enterprise SSO
- `local_noauth` — development convenience
- `hosted` — traditional OAuth flows

Additional security layers include Turnstile CAPTCHAs, API key handling for DataForSEO, and OpenRouter integration for AI agents.

Implementation spans [`src/lib/auth.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/auth.ts), [`src/lib/auth-mode.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/auth-mode.ts), and environment declarations in [`src/env.d.ts`](https://github.com/every-app/open-seo/blob/main/src/env.d.ts).

## Self-Hosting Utilities

OpenSEO includes comprehensive self-hosting support:

| Component | Purpose |
|-----------|---------|
| [`src/lib/selfhost-preflight.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/selfhost-preflight.ts) | Environment validation before startup |
| [`docker-entrypoint.sh`](https://github.com/every-app/open-seo/blob/main/docker-entrypoint.sh) | Container initialization |
| `docs/SELF_HOSTING_*.md` | Deployment guides |

These tools enable private Cloudflare Workers deployments without vendor lock-in.

## Front-End: React with TanStack Query

The UI layer uses React, TanStack Query for data fetching, and Tailwind CSS. It consumes server functions through generated types, maintaining type safety across the API boundary.

The entry point [`src/start.ts`](https://github.com/every-app/open-seo/blob/main/src/start.ts) bootstraps the application.

## Summary

- **Edge runtime**: Cloudflare Workers with TanStack server functions in [`src/server.ts`](https://github.com/every-app/open-seo/blob/main/src/server.ts)
- **Stateful compute**: Three Durable Object families (`AuditScratchpad`, `OnboardingChatAgent`, `SamChatAgent`)
- **Job orchestration**: Workflows in [`src/server/workflows/SiteAuditWorkflow.ts`](https://github.com/every-app/open-seo/blob/main/src/server/workflows/SiteAuditWorkflow.ts) separate compute from state
- **Type-safe API**: Server functions in `src/serverFunctions/` bridge front end and business logic
- **Flexible storage**: Drizzle abstracts D1 SQLite and PostgreSQL in [`src/db/schema.ts`](https://github.com/every-app/open-seo/blob/main/src/db/schema.ts)
- **Multi-mode auth**: `cloudflare_access`, `local_noauth`, and `hosted` via [`src/lib/auth.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/auth.ts)
- **Deployment flexibility**: Self-hosting utilities in [`src/lib/selfhost-preflight.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/selfhost-preflight.ts) and documentation

## Frequently Asked Questions

### What database does OpenSEO use?

OpenSEO supports dual database backends through Drizzle ORM. **Cloudflare D1** (SQLite) provides a serverless default for edge deployments, while **PostgreSQL** accommodates workloads requiring traditional relational features. Schema definitions in [`src/db/schema.ts`](https://github.com/every-app/open-seo/blob/main/src/db/schema.ts) compile to both targets.

### How does OpenSEO handle large site crawls without memory issues?

The platform uses **Workflows** combined with **Durable Objects**. The `SiteAuditWorkflow` leases URL chunks from the `AuditScratchpad` DO, processes them, and stores results back in the DO. This architecture isolates transient crawl state from the workflow's memory, preventing OOM failures and step-limit violations.

### Can OpenSEO run outside Cloudflare's ecosystem?

Yes. The repository includes **self-hosting utilities** including environment validation ([`src/lib/selfhost-preflight.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/selfhost-preflight.ts)), Docker support, and comprehensive documentation. While optimized for Cloudflare Workers, the modular architecture permits alternative deployments with adjusted infrastructure adapters.

### What authentication methods does OpenSEO support?

Three modes are implemented: **Cloudflare Access** for enterprise SSO, **local_noauth** for development, and **hosted** for traditional OAuth flows. The auth system in [`src/lib/auth.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/auth.ts) and [`src/lib/auth-mode.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/auth-mode.ts) dynamically selects behavior based on environment configuration.