OpenSEO Development Workflow: Local Setup to Production Deployment
The OpenSEO development workflow uses a TypeScript monorepo with pnpm, Vite, and Drizzle ORM, enabling contributors to install dependencies, configure a local SQLite database, and start a dev server within minutes using commands like pnpm install, pnpm run db:migrate:local, and pnpm dev:agents.
The every-app/open-seo repository follows a modern TypeScript monorepo pattern designed for rapid SEO tool development. Understanding the OpenSEO development workflow allows you to spin up a full local environment, run automated tests against your changes, and deploy to production using either Docker or Cloudflare Workers.
Prerequisites and Environment Setup
Getting started requires Node.js 20+ and pnpm installed on your machine. The workflow is intentionally lightweight, with environment configuration centralized in specific utility files.
Installing Dependencies
Run pnpm install from the repository root to pull in all packages across the monorepo. This installs Vite, Drizzle ORM, TanStack Server Functions, and development tools defined in the root package.json.
Database Configuration
OpenSEO uses Drizzle ORM to abstract database operations, supporting both SQLite (default) and PostgreSQL. Initialize your local database by running the migration script once after cloning:
pnpm run db:migrate:local
This command invokes the migration logic defined in src/db/runBatch.ts, which applies pending schema changes to your local SQLite instance. For subsequent schema changes, you will generate new migrations using pnpm run db:generate before running the migrate command again.
Environment Variables
Configuration management is handled by scripts/cli-utils.ts, which parses CLI arguments and loads environment files. Copy the example environment file and add your DataForSEO API credentials:
cp .env.example .env.local
Edit .env.local to include your DATAFORSEO_API_KEY as a base64-encoded string (login:password). The CLI utilities in scripts/cli-utils.ts automatically load .env.local or .env depending on your execution context.
Development Server Options
OpenSEO provides two ways to run the development server, catering to different testing needs.
Standard Vite Development
For basic development, run:
pnpm run dev
This starts the Vite development server using the configuration defined in web/vite.config.ts. Standard development uses standard localhost ports.
Portless Development for Agents
The recommended approach for multi-branch testing or AI agent integration uses the portless configuration:
mkdir -p .logs && touch .logs/dev-server.log
pnpm dev:agents
This launches the server at http://open-seo.localhost:1355 using Vercel's portless tool, giving each Git worktree a unique subdomain. Logs pipe automatically to .logs/dev-server.log, and the setup integrates with the MCP (Model Context Protocol) server exposed in src/middleware/*, allowing AI agents like Claude Code to consume SEO data directly.
Project Architecture and Code Organization
The monorepo separates concerns into distinct directories to maintain clarity as the codebase scales.
Server Functions Structure
All backend logic lives in src/serverFunctions/ as TanStack Server Functions. These are thin wrappers that call shared services. For example, the Google Search Console integration in src/serverFunctions/gsc.ts wraps the DataForSEO client:
// src/serverFunctions/gsc.ts
import { createServerFunction } from "@tanstack/server";
import { fetchGscData } from "../lib/gsc-client";
export const getGscOverview = createServerFunction(
async (params: { domain: string }) => {
const data = await fetchGscData(params.domain);
return data;
},
);
Shared business logic resides in src/shared/ (e.g., src/shared/rank-tracking.ts contains core rank-tracking algorithms used by both frontend and backend).
Database Layer with Drizzle ORM
The database abstraction supports multiple backends through src/db/pg/* for PostgreSQL and default SQLite configurations. Migration generation and execution are handled via CLI commands that invoke src/db/runBatch.ts. After modifying any schema files, generate a new migration with:
pnpm run db:generate
Then apply it locally using pnpm run db:migrate:local.
Authentication Modes
OpenSEO supports three distinct authentication modes controlled by the AUTH_MODE environment variable: cloudflare_access, local_noauth, and hosted. The middleware layer in src/middleware/ensure-user/* enforces the selected mode. For Cloudflare Access deployments, validation logic resides in src/middleware/ensure-user/cloudflareAccess.ts, while type definitions are exported from src/middleware/ensure-user/types.ts.
Testing and Quality Assurance
Before submitting changes, run the comprehensive CI check locally:
pnpm ci:check
This executes linting, TypeScript type checking, unit tests via Vitest (configured in vitest.config.ts), and end-to-end tests via Playwright (configured in playwright.config.ts). Test files follow the src/**/*.test.ts pattern throughout the repository.
Contribution and Deployment
The contribution workflow is documented in docs/CONTRIBUTING.md. Keep pull requests focused on single features or bug fixes, and ensure pnpm ci:check passes locally before pushing.
For production deployment, OpenSEO supports two primary methods:
- Docker: Self-host using the provided
Dockerfileand documentation indocs/SELF_HOSTING_DOCKER.md - Cloudflare Workers: Deploy to the edge using configurations in the
cloudflare/directory
Both methods respect the environment variable patterns established in .env.example and the authentication modes defined in the middleware layer.
Summary
- Install dependencies with
pnpm install(requires Node.js 20+) - Configure the database by running
pnpm run db:migrate:localafter cloning - Start development using
pnpm dev:agentsfor portless multi-branch testing orpnpm run devfor standard development - Organize code in
src/serverFunctions/for API endpoints,src/shared/for utilities, andsrc/middleware/for authentication - Test changes with
pnpm ci:checkbefore opening pull requests - Deploy via Docker or Cloudflare Workers using the documented configuration patterns
Frequently Asked Questions
What is the difference between pnpm run dev and pnpm dev:agents?
pnpm run dev starts a standard Vite development server on localhost ports, suitable for basic frontend development. pnpm dev:agents launches a portless instance at http://open-seo.localhost:1355 that generates unique subdomains per Git worktree and pipes logs to .logs/dev-server.log, specifically designed for testing AI agent integrations with the MCP server.
How do I add a new database migration in OpenSEO?
After modifying your Drizzle schema files, run pnpm run db:generate to create a new migration file. Then apply it to your local database using pnpm run db:migrate:local. The migration logic is implemented in src/db/runBatch.ts and handles both SQLite and PostgreSQL backends.
Which authentication mode should I use for local development?
For local development, set AUTH_MODE=local_noauth in your .env.local file. This bypasses authentication checks and allows immediate access to all server functions. For production deployments, choose cloudflare_access (for Cloudflare Zero Trust) or hosted depending on your infrastructure, with validation middleware located in src/middleware/ensure-user/.
Where are the server functions located and how are they structured?
Server functions are grouped in src/serverFunctions/ and implemented as TanStack Server Functions. Each file exports functions created with createServerFunction that wrap shared logic from src/shared/ or external API clients like the DataForSEO client in src/lib/auth-client.ts. This pattern keeps API endpoints type-safe and co-located with their business logic.
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 →