How to Set Up a Development Environment for OpenSEO: Complete Local Setup Guide

Clone the repository, install Node 20+ and pnpm, run pnpm install and pnpm run db:migrate:local, configure .env.local with your base64-encoded DataForSEO API key, and launch the development server using pnpm dev:agents to emulate the Cloudflare Workers runtime.

OpenSEO is an open-source SEO platform built on Cloudflare Workers using the Vite runtime, Drizzle ORM, and supports both Cloudflare D1 (SQLite) and PostgreSQL backends according to the every-app/open-seo repository. Setting up a local development environment requires Node 20+, pnpm, and specific API credentials to fetch live SEO data.

Prerequisites

Before cloning the repository, ensure your system meets these requirements:

  • Node.js 20 or higher: Required for the server code and build tooling.
  • pnpm: The project uses pnpm workspaces for fast, lock-file-consistent dependency management.
  • DataForSEO API credentials: You need a base64-encoded login:password token to fetch SEO data.
  • Docker (optional): Only required if running the PostgreSQL backend locally instead of the default D1 SQLite database.

As documented in docs/LOCAL_DEVELOPMENT.md in the source code, these prerequisites are mandatory for the local development workflow.

Step 1: Clone and Install Dependencies

Start by cloning the repository and installing workspace dependencies:

git clone https://github.com/every-app/open-seo.git
cd open-seo
pnpm install

The pnpm install command installs both the web UI (web/) and server (src/) workspace packages defined in the pnpm workspace configuration.

Step 2: Initialize the Local Database

OpenSEO defaults to Cloudflare D1 (SQLite) for local development. Generate the schema and apply migrations:

pnpm run db:migrate:local

This command reads the schema definitions under src/db/ and creates a D1-compatible SQLite file locally. The migration tool is idempotent—it checks for already-applied migrations before executing new ones.

Step 3: Configure Environment Variables

Copy the example environment file and configure your DataForSEO credentials:

cp .env.example .env.local

Generate a base64-encoded API key from your DataForSEO login credentials:

printf '%s' 'YOUR_LOGIN:YOUR_PASSWORD' | base64

Add the resulting string to .env.local:

DATAFORSEO_API_KEY=dX...==

As documented in docs/SELF_HOSTING_CLOUDFLARE.md, these secrets can also be managed via the Cloudflare dashboard when self-hosting, but .env.local is required for local development.

Step 4: Choose an Authentication Mode

The OpenSEO source code in src/ supports three authentication modes controlled via the AUTH_MODE environment variable:

  • local_noauth: Disables authentication and injects a trusted admin@localhost identity. This is automatically set by the pnpm dev and pnpm dev:agents scripts for rapid local development.
  • cloudflare_access: Validates Cloudflare Access JWTs (cf-access-jwt-assertion) using TEAM_DOMAIN and POLICY_AUD variables. Use this for production-like testing of Cloudflare Access.
  • hosted: Enables Better Auth email/password flow requiring BETTER_AUTH_SECRET and BETTER_AUTH_URL. Use this to exercise the full hosted authentication stack locally.

To test Cloudflare Access locally, explicitly set the mode:

AUTH_MODE=cloudflare_access pnpm dev

Step 5: Start the Development Server

OpenSEO provides two development server options depending on your testing needs.

Option 1: Simple Vite Dev Server

pnpm run dev

This starts the worker at http://localhost:5173 using the Vite runtime. While suitable for quick UI iteration, this method does not emulate Cloudflare's routing model.

Option 2: Portless Workflow (Recommended)

mkdir -p .logs && touch .logs/dev-server.log
pnpm dev:agents

The portless tool proxies requests to http://open-seo.localhost:1355 and mirrors the Cloudflare runtime environment, including environment bindings and hostnames. Raw worker logs are written to .logs/dev-server.log for easier debugging.

Step 6: Switch to PostgreSQL (Optional)

If you outgrow the D1 SQLite limits, switch to a PostgreSQL backend using Docker.

Start the PostgreSQL container on port 5433 to avoid conflicts:

docker run --name openseo-postgres \
  -e POSTGRES_USER=openseo \
  -e POSTGRES_PASSWORD=openseo \
  -e POSTGRES_DB=openseo \
  -p 5433:5432 \
  -d postgres:16

Wait for readiness:

docker exec openseo-postgres pg_isready -U openseo -d openseo

Apply PostgreSQL migrations (stored in drizzle-pg/):

POSTGRES_DATABASE_URL=postgres://openseo:openseo@localhost:5433/openseo \
  pnpm db:migrate:pg

Configure the provider in .env.local:

DATABASE_PROVIDER=postgres

The Vite runtime reads this flag from .env.local and maps the HYPERDRIVE binding to your connection string defined in wrangler.jsonc. No code changes are required. To revert to D1, set DATABASE_PROVIDER=d1 and restart.

Summary

  • Install Node 20+ and pnpm, then run pnpm install to populate workspace dependencies in the web/ and src/ directories.
  • Initialize the local database with pnpm run db:migrate:local for SQLite/D1 development, which reads schemas from src/db/.
  • Configure DataForSEO API credentials in .env.local using base64 encoding of your login:password string.
  • Use pnpm dev:agents to run the portless workflow that emulates Cloudflare Workers runtime at open-seo.localhost:1355.
  • Switch to PostgreSQL by running a Docker container on port 5433, applying migrations with pnpm db:migrate:pg (which uses files in drizzle-pg/), and setting DATABASE_PROVIDER=postgres.
  • Select the appropriate AUTH_MODE (local_noauth, cloudflare_access, or hosted) based on your authentication testing requirements.

Frequently Asked Questions

What Node.js version is required for OpenSEO development?

OpenSEO requires Node.js 20 or higher to run the server code and development tooling. This version ensures compatibility with the Vite-powered Cloudflare Workers runtime and pnpm workspaces used throughout the every-app/open-seo codebase.

How do I switch between SQLite and PostgreSQL in local development?

By default, OpenSEO uses Cloudflare D1 (SQLite) via src/db/ schemas. To switch to PostgreSQL, start a Docker container on port 5433, run pnpm db:migrate:pg to apply the schema from drizzle-pg/, and set DATABASE_PROVIDER=postgres in .env.local. The Vite runtime automatically reconfigures the HYPERDRIVE binding in wrangler.jsonc without code changes. Revert by setting DATABASE_PROVIDER=d1.

What's the difference between pnpm dev and pnpm dev:agents?

pnpm dev starts a basic Vite server at localhost:5173 for quick UI work but does not emulate Cloudflare's routing. pnpm dev:agents uses the portless tool to proxy requests to open-seo.localhost:1355, accurately mimicking the Cloudflare Workers runtime with proper environment bindings and logging to .logs/dev-server.log.

How do I authenticate with DataForSEO for local development?

You need a base64-encoded string of your DataForSEO login:password credentials. Generate this using printf '%s' 'LOGIN:PASSWORD' | base64, then add the result to DATAFORSEO_API_KEY in .env.local. This token enables the application to fetch SEO data from the DataForSEO API during development.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →