# Open-SEO Project Structure: A Complete Guide to the Root Directory Layout

> Explore the Open-SEO project structure and root directory layout. Understand the organization of this TypeScript monorepo, featuring Vite React frontend and Cloudflare Workers backend.

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

---

**Open-SEO is a TypeScript monorepo that combines a Vite-based React frontend with Cloudflare Workers backend, organized into directories like `src/`, `web/`, `drizzle/`, and `e2e/` at the repository root.**

The `every-app/open-seo` repository implements a modern SEO analytics platform as a tightly-coupled full-stack application. Understanding the open-seo project structure is essential for contributors and self-hosters navigating the Cloudflare Workers ecosystem. The root layout separates concerns between frontend routing, serverless functions, database schema, and static assets while maintaining a unified build pipeline managed by Vite and Wrangler.

## Root-Level Directory Overview

At the repository root, code is partitioned into functional groups that handle distinct architectural concerns:

- **`src/`** – Core application code including React components, TanStack Router configuration, server functions, database schema definitions, and shared utilities
- **`web/`** – Dedicated workspace for the Vite frontend containing its own [`package.json`](https://github.com/every-app/open-seo/blob/main/package.json), pnpm workspace configuration, and Cloudflare-specific worker bindings
- **`drizzle/`** – Database migration scripts and schema evolution files for the D1 SQLite database used by the Workers runtime
- **`e2e/`** – End-to-end test suites executed with Playwright against the full stack
- **`docs/`** – Human-readable documentation covering self-hosting guides, local development setup, and maintainer notes
- **`scripts/`** – Utility scripts for data seeding, billing report generation, and operational tasks
- **`public/`** – Static assets served by the Vite dev server including icons, manifests, and other build-time resources
- **`specs/`** – Design specification documents that drive feature development
- **`release-notes/`** – Markdown changelogs documenting version history

## Core Architectural Layers

The open-seo project structure implements five distinct layers that bridge frontend interactions with serverless backend operations.

### Frontend Layer (React + Vite)

The user interface resides under `src/routes/*` and `src/components/*`, with the entry point at [`src/router.tsx`](https://github.com/every-app/open-seo/blob/main/src/router.tsx). This file declares the client-side route tree using **TanStack Router**, enabling type-safe navigation throughout the application.

### Backend Layer (Cloudflare Workers)

Server-side logic is exposed through **Server Functions** located in `src/serverFunctions/*.ts`. These TypeScript modules are automatically mapped to HTTP endpoints by the Workers runtime. When the frontend invokes these functions via `fetch` requests, Cloudflare handles the routing without requiring explicit API route definitions.

### Database Layer (Drizzle ORM + D1)

Database schema definitions live in [`src/db/schema.ts`](https://github.com/every-app/open-seo/blob/main/src/db/schema.ts) alongside per-entity schema files. The `drizzle/` directory contains SQL migration files that evolve the SQLite-compatible D1 database schema. Migrations are applied using Wrangler commands (`npm run db:migrate:*`).

### Authentication & Authorization

Auth utilities are implemented in `src/lib/*`, supporting three distinct modes: local no-auth development, Cloudflare Access integration, and custom OAuth providers. Bindings are declared in [`package.json`](https://github.com/every-app/open-seo/blob/main/package.json) under the `cloudflare.bindings` key.

### MCP (Machine-Client Protocol)

The MCP endpoint for AI agent integration is implemented in `src/server/mcp/*`, allowing programmatic access to Open-SEO functionality via standardized protocol handlers.

## Key Configuration Files

Several root-level files orchestrate the build and deployment pipeline:

- **`wrangler.jsonc`** – Configures Cloudflare Workers bindings, routes, and environment variables for the serverless runtime
- **[`vite.config.ts`](https://github.com/every-app/open-seo/blob/main/vite.config.ts)** – Defines Vite build settings including the Cloudflare plugin that bridges frontend and backend during development
- **[`package.json`](https://github.com/every-app/open-seo/blob/main/package.json)** – Declares workspace dependencies, scripts for database migrations, and Cloudflare-specific metadata
- **[`tsconfig.json`](https://github.com/every-app/open-seo/blob/main/tsconfig.json)** – Establishes TypeScript compiler options for the entire monorepo

## Working with the Codebase

Understanding how to navigate the open-seo project structure requires familiarity with its serverless function patterns and database workflows.

### Importing Server Functions

Frontend components consume backend logic through direct imports of server function modules. The build system handles the network boundary automatically.

```typescript
// src/routes/_app/projects.tsx
import { useQuery } from '@tanstack/react-query';
import { getProjects } from '~/serverFunctions/projects';

// Fetch the list of projects when the component mounts
const { data: projects, isLoading } = useQuery(['projects'], getProjects);

```

*See [`src/serverFunctions/projects.ts`](https://github.com/every-app/open-seo/blob/main/src/serverFunctions/projects.ts) for the implementation.*

### Defining New Server Functions

Creating new API endpoints involves exporting request handlers from the `src/serverFunctions/` directory. These functions become accessible at `/api/` routes automatically.

```typescript
// src/serverFunctions/keywords.ts
import { json } from '@cloudflare/workers-types';
import { fetchKeywordData } from '~/shared/keyword-data';

// Exported function is auto-exposed as a route `/api/keywords`
export async function onRequest(context: any) {
  const { query } = await context.request.json();
  const result = await fetchKeywordData(query);
  return json(result);
}

```

*The function becomes reachable at `https://<your-domain>/api/keywords`.*

### Running Database Migrations

Schema changes are managed through Drizzle ORM migration files stored in `drizzle/`:

```bash

# Apply all pending D1 migrations locally

npm run db:migrate:local

```

*The migration files are orchestrated by `wrangler d1 migrations` and target the SQLite-compatible D1 database.*

## Summary

- **Open-SEO** organizes code into `src/` (application logic), `web/` (frontend workspace), and `drizzle/` (database migrations) at the repository root
- The architecture combines **React with TanStack Router** on the frontend and **Cloudflare Workers Server Functions** on the backend
- Database operations use **Drizzle ORM** with SQLite-compatible D1, with migration files stored in `drizzle/`
- Configuration is centralized in `wrangler.jsonc` (Workers), [`vite.config.ts`](https://github.com/every-app/open-seo/blob/main/vite.config.ts) (build), and [`package.json`](https://github.com/every-app/open-seo/blob/main/package.json) (workspace)
- End-to-end testing is handled by Playwright in the `e2e/` directory, while unit tests reside alongside source files in `src/**/*.test.ts`

## Frequently Asked Questions

### What is the purpose of the `web/` directory in Open-SEO?

The `web/` directory serves as a dedicated workspace for the Vite frontend, containing its own [`package.json`](https://github.com/every-app/open-seo/blob/main/package.json) and Cloudflare-specific worker configuration. This separation allows the frontend build process to maintain independent dependency management while still integrating with the monorepo's shared configuration and build pipeline.

### How are backend API routes defined in the Open-SEO project structure?

Backend routes are defined implicitly through **Server Functions** in `src/serverFunctions/*.ts` rather than explicit routing files. When you export an `onRequest` function from a module in this directory, the Cloudflare Workers runtime automatically exposes it as an HTTP endpoint accessible via `/api/` paths, eliminating the need for separate route definitions.

### Where are database schema changes managed in Open-SEO?

Database schema is defined in [`src/db/schema.ts`](https://github.com/every-app/open-seo/blob/main/src/db/schema.ts) using Drizzle ORM syntax, while migration files are stored in the `drizzle/` directory at the repository root. The `wrangler.jsonc` configuration points to these migrations, which are applied to the D1 SQLite database using npm scripts like `db:migrate:local` or `db:migrate:production`.

### What testing strategies does the Open-SEO project structure support?

The repository implements a two-tier testing approach: **unit tests** written alongside source code in `src/**/*.test.ts` and executed with Vitest, and **end-to-end tests** located in the `e2e/` directory that use Playwright to verify complete user workflows across the React frontend and Cloudflare Workers backend integration.