OpenSEO Project Structure: Full-Stack TanStack Architecture Explained
OpenSEO is a full-stack TypeScript application built on TanStack React-Start and Drizzle ORM, organized into distinct layers for UI rendering, server functions, background workflows, and database access that deploys to Cloudflare Workers.
OpenSEO is an open-source SEO platform that combines a React-based user interface with serverless backend architecture. Understanding the open-seo project structure helps developers navigate the codebase for self-hosting, contributions, or custom integrations. The repository follows a clear separation of concerns across entry points, routing, API functions, workflows, and data layers while maintaining end-to-end type safety.
Entry Points and Application Bootstrap
The application initializes through two main entry points that handle different runtime contexts.
TanStack React-Start Setup
The src/start.ts file bootstraps the TanStack React-Start instance with CSRF middleware protection. It creates the startInstance using createStart and createCsrfMiddleware from @tanstack/react-start, establishing the foundation for server-rendered React applications.
Cloudflare Workers Handler
The src/server.ts file serves as the Cloudflare Workers entry point, exposing the main fetch function that routes incoming requests. This handler supports three authentication modes—hosted, cloudflare_access, and local_noauth—and delegates requests to either the MCP (Meta Control Plane), OAuth provider, or the TanStack UI layer via appFetch.
Routing and Type Safety
Auto-Generated Route Tree
The routing system relies on src/routeTree.gen.ts, an auto-generated file produced by TanStack Router. This provides compile-time type safety for all routes defined in src/routes/..., enabling type-safe navigation and URL generation throughout the application.
The following example demonstrates type-safe navigation using the generated route tree:
// Use the typed route tree for navigation in a React component
import { Link, useNavigate } from '@tanstack/react-router';
import { routeTree } from '@/routeTree.gen';
function NavBar() {
const navigate = useNavigate();
return (
<nav>
<Link to={routeTree.projects}>Projects</Link>
<button onClick={() => navigate({ to: routeTree.settings })}>
Settings
</button>
</nav>
);
}
API Surface: Server Functions
MCP-Integrated Endpoints
The API layer resides in src/serverFunctions/*.ts (e.g., keywords.ts, rank-tracking.ts, audit.ts). These functions are wrapped by globalServerFunctionMiddleware (registered in src/start.ts) and expose REST-like endpoints that the UI consumes via await $someServerFunction(args). This pattern enables seamless client-server communication with full TypeScript inference.
Server functions execute within the same Worker context as the main application, sharing database connections and returning typed JSON responses.
// Call a server function from the UI (e.g., fetch keyword suggestions)
import { $keywords } from '@/serverFunctions/keywords';
async function getSuggestions(query: string) {
const result = await $keywords.search({ query });
return result.suggestions; // typed array of strings
}
Background Processing Layer
Workflow Implementations
Long-running operations like site audits and rank checks are implemented as workflow classes in src/server/workflows/. Files like SiteAuditWorkflow.ts and RankCheckWorkflow.ts define background jobs that execute via Cloudflare Durable Objects or scheduled Workers (triggered through the scheduled export in src/server.ts).
You can trigger workflows directly from server functions:
// Schedule a rank-check workflow from a server function
import { runScheduledRankChecks } from '@/server/features/rank-tracking/services/scheduledRankChecks';
export const $rankTracking = {
async schedule(projectId: string) {
// This runs inside the Worker and uses the same DB connection
await runScheduledRankChecks({ PROJECT_ID: projectId });
return { status: 'queued' };
},
};
Database Architecture
Drizzle Schema and Multi-Provider Support
The data layer uses Drizzle ORM with support for both SQLite (D1) and PostgreSQL. Key files include:
src/db/schema.ts- Core schema definitionssrc/db/pg/*.ts- PostgreSQL-specific client implementations (pg/client.ts)drizzle-pg/- Schema duplicates for PostgreSQL targets
All database interactions are typed, providing compile-time safety for queries executed within server functions and workflows.
Authentication and Security
Multi-Mode Auth System
Authentication is centralized in src/lib/auth-config.ts and related files, supporting:
- Hosted SaaS authentication via
createOpenSeoOAuthProvider - Cloudflare Access integration
- Local development mode (
local_noauth) - Turnstile captcha validation and session management
Middleware in src/middleware/ensure-user/*.ts handles route protection based on the active auth mode.
Request Flow Through the Architecture
Understanding how requests traverse the open-seo project structure:
-
Entry: Cloudflare Workers invoke
src/server.ts, wrapping requests with PostgreSQL clients (withPgClient) and determining auth mode viagetAuthMode. -
Routing Logic: The server handler categorizes requests:
/agents/*→ Durable Object chat agents (routeChatAgents)/auth/*→ OpenSEO OAuth provider (openSeoOAuthProvider)/api/*or/api/gsc/oauth/callback→ Self-hosted MCP handler (handleSelfHostedOpenSeoMcpRequest)- All others → TanStack React-Start UI (
appFetch)
-
Execution: UI components call server functions which execute within the same Worker context, sharing database connections and returning typed JSON responses.
-
Background Jobs: Workflows trigger via direct API calls or the Worker's
scheduledhandler, processing tasks like site audits asynchronously.
Shared Utilities and Documentation
Cross-Cutting Concerns
Pure utility functions for SEO data processing, billing calculations, and Google Search Console integrations live in src/shared/*.ts. These modules are unit-tested with co-located *.test.ts files.
Documentation and Deployment
Self-hosting guides in docs/SELF_HOSTING_DOCKER.md provide Docker deployment instructions, while scripts/*.ts contains migration utilities and data seeding tools. End-to-end testing uses Playwright (e2e/*.spec.ts) to validate critical user flows.
Summary
- Layered Architecture: OpenSEO separates UI (TanStack React-Start), API (Server Functions), background processing (Workflows), and data (Drizzle) into distinct, typed layers.
- Cloudflare-Native: The entire stack runs on Cloudflare Workers, using
src/server.tsas the entry point with support for Durable Objects and scheduled jobs. - Type Safety: Auto-generated routing (
routeTree.gen.ts) and Drizzle ORM provide end-to-end TypeScript safety from database to UI. - Flexible Auth: Supports hosted SaaS, Cloudflare Access, and local development modes through centralized auth utilities in
src/lib/auth-*.ts. - Self-Host Ready: Comprehensive Docker documentation and modular server functions make deployment straightforward for self-hosted instances.
Frequently Asked Questions
What framework does OpenSEO use for the frontend?
OpenSEO uses TanStack React-Start, a server-rendered React framework that provides file-based routing and server functions. The entry point in src/start.ts initializes the application with CSRF protection, while src/routeTree.gen.ts provides compile-time type safety for all routes.
How does OpenSEO handle background tasks like site audits?
Background tasks are implemented as Workflows in src/server/workflows/. Classes like SiteAuditWorkflow.ts and RankCheckWorkflow.ts define long-running jobs that execute via Cloudflare Durable Objects or the Worker's scheduled export. These workflows share the same Drizzle database connection as the main application.
Can I self-host OpenSEO without using the hosted version?
Yes. The codebase supports three authentication modes including local_noauth for development and self-hosted deployments. The repository includes docs/SELF_HOSTING_DOCKER.md with Docker deployment instructions, and the MCP (Meta Control Plane) handlers in src/server.ts can process self-hosted API requests independently of the hosted SaaS infrastructure.
How is the database structured in OpenSEO?
OpenSEO uses Drizzle ORM with a multi-provider architecture supporting both Cloudflare D1 (SQLite) and PostgreSQL. Schema definitions live in src/db/schema.ts with PostgreSQL-specific implementations in src/db/pg/. The database layer provides typed query APIs used by server functions and workflows, ensuring type safety across the entire data access layer.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →