# Open-SEO Components Explained: A Full-Stack TypeScript Architecture Breakdown

> Explore Open-SEO's full-stack TypeScript architecture. Understand its seven core components from routing to project management in this detailed breakdown of the every-app/open-seo repository.

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

---

**Open-SEO is a full-stack SEO platform built with TanStack Router, React, and Cloudflare Workers, organized into seven core layers: routing and UI, typed server functions, database abstraction, middleware and auth, client feature modules, self-hosting utilities, and project management.**

The `every-app/open-seo` repository implements a clean separation between frontend and backend concerns, using **typed server functions** as the primary communication bridge. This architecture enables deployment to Cloudflare's edge or self-hosted Node environments while maintaining full type safety across the stack.

## Routing and UI Layout Components

The application's navigation and visual structure are centralized in two key files:

- **[`src/router.tsx`](https://github.com/every-app/open-seo/blob/main/src/router.tsx)** — Defines the TanStack Router configuration, including lazy-loaded route modules and global middleware hooks
- **[`src/client/layout/AppShell.tsx`](https://github.com/every-app/open-seo/blob/main/src/client/layout/AppShell.tsx)** — Provides the persistent UI frame (sidebar, header, navigation) wrapped around all route content

This pattern keeps routing logic decoupled from business logic, enabling true single-page-app behavior with code-splitting at the route level.

## Server Functions: The Typed API Layer

All backend operations are implemented as **self-contained server functions** in `src/serverFunctions/*.ts`, exposed through `createServerFn`. Each function validates inputs with **Zod** and executes on the worker runtime.

### Core Domain Server Functions

| Domain | File Path | Key Operations |
|--------|-----------|--------------|
| Projects | [`src/serverFunctions/projects.ts`](https://github.com/every-app/open-seo/blob/main/src/serverFunctions/projects.ts) | `createProject`, `getProjects`, `updateProject`, `archiveProject` |
| Keyword Research | [`src/serverFunctions/keywords.ts`](https://github.com/every-app/open-seo/blob/main/src/serverFunctions/keywords.ts) | `researchKeywords`, `saveKeywords` |
| Rank Tracking | [`src/serverFunctions/rank-tracking.ts`](https://github.com/every-app/open-seo/blob/main/src/serverFunctions/rank-tracking.ts) | `getRankTrackingConfigs`, `addTrackingKeywords`, `getRankHistory` |
| Search Performance | [`src/serverFunctions/searchPerformance.ts`](https://github.com/every-app/open-seo/blob/main/src/serverFunctions/searchPerformance.ts) | `getSearchPerformanceReport` |
| Backlinks | [`src/serverFunctions/backlinks.ts`](https://github.com/every-app/open-seo/blob/main/src/serverFunctions/backlinks.ts) | `getBacklinksOverview`, `getBacklinksRows` |
| Google Search Console | [`src/serverFunctions/gsc.ts`](https://github.com/every-app/open-seo/blob/main/src/serverFunctions/gsc.ts) | `listGscSites`, `setGscSite`, `verifyGscOwnership` |
| Audits | [`src/serverFunctions/audit.ts`](https://github.com/every-app/open-seo/blob/main/src/serverFunctions/audit.ts) | `startAudit`, `getAuditStatus` |
| Lighthouse | [`src/serverFunctions/lighthouse.ts`](https://github.com/every-app/open-seo/blob/main/src/serverFunctions/lighthouse.ts) | `getAuditLighthouseIssues` |
| AI Assist (SAM) | [`src/serverFunctions/sam.ts`](https://github.com/every-app/open-seo/blob/main/src/serverFunctions/sam.ts) | `createSamSession`, `listSamSessions`, `sendSamMessage` |
| Billing | [`src/serverFunctions/billing.ts`](https://github.com/every-app/open-seo/blob/main/src/serverFunctions/billing.ts) | `getBillingUsageEvents`, `getCurrentPlan` |
| Onboarding | [`src/serverFunctions/onboardingChat.ts`](https://github.com/every-app/open-seo/blob/main/src/serverFunctions/onboardingChat.ts) | `getOnboardingChatState`, `advanceOnboardingStep` |

These functions are consumed by the UI through TanStack Query, providing automatic caching, background refetching, and error handling.

### Example: Calling a Server Function

```tsx
import { useQuery } from "@tanstack/react-query";
import { getRankTrackingConfigs } from "@/serverFunctions/rank-tracking";

export function RankTrackingLoader({ projectId }: { projectId: string }) {
  const { data, isLoading } = useQuery({
    queryKey: ["rankTrackingConfigs", projectId],
    queryFn: () => getRankTrackingConfigs({ data: { projectId } })
  });

  if (isLoading) return <Spinner />;
  
  return <RankTrackingTable configs={data?.configs ?? []} />;
}

```

## Database Layer with Drizzle ORM

Open-SEO abstracts database access through **Drizzle ORM**, supporting both **SQLite (via Cloudflare D1)** and **PostgreSQL** through dialect-specific schemas.

- **[`src/db/schema.ts`](https://github.com/every-app/open-seo/blob/main/src/db/schema.ts)** — Shared table definitions and types
- **[`src/db/pg/schema.ts`](https://github.com/every-app/open-seo/blob/main/src/db/pg/schema.ts)** — PostgreSQL-specific column types
- **[`src/db/d1/schema.ts`](https://github.com/every-app/open-seo/blob/main/src/db/d1/schema.ts)** — D1 SQLite adaptations
- **[`src/db/provider.ts`](https://github.com/every-app/open-seo/blob/main/src/db/provider.ts)** — Runtime client creation based on `DATABASE_URL`
- **[`src/db/telemetry.schema.ts`](https://github.com/every-app/open-seo/blob/main/src/db/telemetry.schema.ts)** — Observability tables
- **[`src/db/audit.schema.ts`](https://github.com/every-app/open-seo/blob/main/src/db/audit.schema.ts)** — Audit log storage

All schemas are strongly typed, ensuring server functions receive correctly-shaped data without runtime surprises.

### Schema Definition Example

```ts
// src/db/schema.ts
import { pgTable, serial, text, varchar } from "drizzle-orm/pg-core";

export const project = pgTable("project", {
  id: serial("id").primaryKey(),
  name: varchar("name", { length: 255 }).notNull(),
  domain: varchar("domain", { length: 255 }).notNull(),
  market: varchar("market", { length: 2 }).notNull(),
});

```

## Middleware and Authentication Components

Request lifecycle management lives in dedicated middleware files:

- **[`src/middleware/errorHandling.ts`](https://github.com/every-app/open-seo/blob/main/src/middleware/errorHandling.ts)** — Global error capture and formatting
- **[`src/middleware/ensure-user/hosted.ts`](https://github.com/every-app/open-seo/blob/main/src/middleware/ensure-user/hosted.ts)** — Self-hosted authentication flow
- **[`src/middleware/ensure-user/delegated.ts`](https://github.com/every-app/open-seo/blob/main/src/middleware/ensure-user/delegated.ts)** — External identity provider integration
- **[`src/middleware/ensure-user/cloudflare-access.ts`](https://github.com/every-app/open-seo/blob/main/src/middleware/ensure-user/cloudflare-access.ts)** — Cloudflare Access headless authentication
- **[`src/lib/auth.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/auth.ts)** — Core authentication utilities
- **[`src/lib/auth-session.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/auth-session.ts)** — Session management
- **[`src/lib/auth-redirect.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/auth-redirect.ts)** — Login flow routing

Every server function receives a validated **`authContext`** containing the authenticated user, active project, and subscription plan before executing business logic.

## Client-Side Feature Modules

Product functionality is organized by vertical under `src/client/features/`, each with its own component tree and data-fetching logic:

| Feature | Primary Components |
|--------|--------------------|
| Rank Tracking | [`RankTrackingTable.tsx`](https://github.com/every-app/open-seo/blob/main/RankTrackingTable.tsx), [`RankTrackingChart.tsx`](https://github.com/every-app/open-seo/blob/main/RankTrackingChart.tsx), [`RankTrackingFilters.tsx`](https://github.com/every-app/open-seo/blob/main/RankTrackingFilters.tsx) |
| Keyword Research | [`SavedKeywordsTable.tsx`](https://github.com/every-app/open-seo/blob/main/SavedKeywordsTable.tsx), [`TagChip.tsx`](https://github.com/every-app/open-seo/blob/main/TagChip.tsx), [`SavedKeywordsFilters.tsx`](https://github.com/every-app/open-seo/blob/main/SavedKeywordsFilters.tsx) |
| Search Performance | [`SearchPerformancePage.tsx`](https://github.com/every-app/open-seo/blob/main/SearchPerformancePage.tsx), [`SearchPerformanceColumns.tsx`](https://github.com/every-app/open-seo/blob/main/SearchPerformanceColumns.tsx) |
| Backlinks | [`BacklinksPage.tsx`](https://github.com/every-app/open-seo/blob/main/BacklinksPage.tsx), [`BacklinksFilterPanel.tsx`](https://github.com/every-app/open-seo/blob/main/BacklinksFilterPanel.tsx), [`BacklinksCharts.tsx`](https://github.com/every-app/open-seo/blob/main/BacklinksCharts.tsx) |
| AI Assist (SAM) | [`SamChat.tsx`](https://github.com/every-app/open-seo/blob/main/SamChat.tsx), [`SamConversation.tsx`](https://github.com/every-app/open-seo/blob/main/SamConversation.tsx) |
| Onboarding | [`OnboardingChat.tsx`](https://github.com/every-app/open-seo/blob/main/OnboardingChat.tsx), [`SearchConsoleOnboardingStep.tsx`](https://github.com/every-app/open-seo/blob/main/SearchConsoleOnboardingStep.tsx) |
| Billing & Settings | [`billing.tsx`](https://github.com/every-app/open-seo/blob/main/billing.tsx), [`settings.tsx`](https://github.com/every-app/open-seo/blob/main/settings.tsx) |

Components communicate with server functions exclusively through **TanStack Query hooks**, ensuring consistent loading, error, and caching behavior.

### Example: Keyword Research Implementation

```ts
import { researchKeywords } from "@/serverFunctions/keywords";

export async function runKeywordResearch(
  projectId: string, 
  seed: string
): Promise<Keyword[]> {
  const result = await researchKeywords({
    data: { 
      projectId, 
      seedKeyword: seed, 
      limit: 50 
    }
  });
  
  return result.keywords;
}

```

## Self-Hosting and Deployment Components

For operators deploying outside Cloudflare, Open-SEO includes:

- **[`src/lib/selfhost-preflight.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/selfhost-preflight.ts)** — Validates environment variables, database connectivity, and service dependencies before application startup
- **`wrangler.jsonc`** — Cloudflare Workers deployment configuration
- **`.env.example`** — Documented environment variables for local development and self-hosting

The preflight module prevents runtime failures by failing fast on misconfiguration.

## Project and Settings Management

Projects serve as the **top-level data container** for all SEO operations. The project subsystem includes:

- **`ProjectSwitcher`** — Cross-project navigation
- **`ProjectSettings`** — Domain, market, and notification configuration
- **`ProjectMarketFields`** — Regional targeting controls

All project operations route through [`src/serverFunctions/projects.ts`](https://github.com/every-app/open-seo/blob/main/src/serverFunctions/projects.ts) with proper authorization checks.

### Example: Creating a Project

```tsx
import { createProject } from "@/serverFunctions/projects";
import { useMutation, useQueryClient } from "@tanstack/react-query";

function NewProjectForm() {
  const queryClient = useQueryClient();
  
  const mutation = useMutation({
    mutationFn: (payload: { name: string; domain: string }) =>
      createProject({ data: payload }),
    onSuccess: () => queryClient.invalidateQueries({ queryKey: ["projects"] })
  });

  // Form implementation omitted...
}

```

## Summary

- **Open-SEO components** are organized into seven architectural layers: routing/layout, server functions, database, middleware/auth, client features, self-hosting, and project management
- **Typed server functions** in `src/serverFunctions/*.ts` form the API layer, with Zod validation and Cloudflare Workers execution
- **Drizzle ORM** provides database abstraction for both SQLite (D1) and PostgreSQL with full type safety
- **Authentication middleware** ensures every request carries a validated `authContext`
- **React feature modules** under `src/client/features/*` implement vertical product functionality using TanStack Query
- **Self-hosting support** includes preflight checks and environment configuration for Node-based deployment

## Frequently Asked Questions

### What framework does Open-SEO use for routing?

Open-SEO uses **TanStack Router** as its primary routing solution. The router is configured in [`src/router.tsx`](https://github.com/every-app/open-seo/blob/main/src/router.tsx) with lazy-loaded route modules and global middleware, providing type-safe routing and code-splitting for the React frontend.

### Can Open-SEO run without Cloudflare?

Yes. While optimized for **Cloudflare Workers**, Open-SEO supports **self-hosted Node.js deployment** through [`src/lib/selfhost-preflight.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/selfhost-preflight.ts), which validates all required environment variables and service connections before startup. The database layer abstracts D1 SQLite and PostgreSQL equally.

### How are API endpoints secured in Open-SEO?

Every server function passes through **authentication middleware** in `src/middleware/ensure-user/*` before execution. The middleware validates the session and attaches an `authContext` object containing the user, project, and plan. There are no unauthenticated server function entry points.

### What ORM does Open-SEO use for database operations?

Open-SEO uses **Drizzle ORM** with dialect-specific schemas in [`src/db/schema.ts`](https://github.com/every-app/open-seo/blob/main/src/db/schema.ts), [`src/db/pg/schema.ts`](https://github.com/every-app/open-seo/blob/main/src/db/pg/schema.ts), and [`src/db/d1/schema.ts`](https://github.com/every-app/open-seo/blob/main/src/db/d1/schema.ts). The provider module at [`src/db/provider.ts`](https://github.com/every-app/open-seo/blob/main/src/db/provider.ts) instantiates the correct client based on the `DATABASE_URL` environment variable, enabling seamless switching between SQLite and PostgreSQL backends.