How to Set Up a Development Environment for OpenSEO: Complete Developer Guide
Install Node 20+ and pnpm, clone the repository, install dependencies with pnpm install, initialize the SQLite database with pnpm run db:migrate:local, configure your DataForSEO API key in .env.local, and run pnpm dev:agents to start the Vite-powered development server.
OpenSEO is an open-source SEO platform built for Cloudflare Workers using Node 20+, pnpm workspaces, and Drizzle ORM. To set up a development environment for OpenSEO, you will configure a local SQLite database (or optional PostgreSQL), set up authentication modes, and run a Vite-powered worker that mimics the Cloudflare production runtime. This guide walks through the exact steps documented in the every-app/open-seo repository.
Prerequisites
Before you begin, ensure you have the following installed:
- Node 20+ – Required runtime for the server code and tooling.
- pnpm – The project uses pnpm workspaces for fast, lock-file-consistent installs.
- DataForSEO API credentials – OpenSEO fetches SEO data from DataForSEO; you need a base64-encoded
login:passwordtoken. - Docker (optional) – Needed only if you want to run the PostgreSQL backend locally instead of the default Cloudflare D1 SQLite.
Step-by-Step Setup
Clone the Repository
Start by cloning the OpenSEO repository and navigating into the project directory:
git clone https://github.com/every-app/open-seo.git
cd open-seo
Install Dependencies
Run pnpm to install both the web UI (web/) and server (src/) workspace packages:
pnpm install
Initialize the Local Database
OpenSEO uses Drizzle ORM with a Cloudflare D1-compatible SQLite backend by default. Generate the schema and apply migrations:
pnpm run db:migrate:local
This command reads the schema definitions under src/db/ and creates a local SQLite file. It is safe to re-run, as the tool checks for already-applied migrations.
Configure Environment Variables
Copy the example environment file and add your DataForSEO credentials:
cp .env.example .env.local
Encode your DataForSEO login:password with base64 and add it to .env.local:
printf '%s' 'YOUR_LOGIN:YOUR_PASSWORD' | base64
Insert the resulting string into .env.local:
DATAFORSEO_API_KEY=dX...==
According to the docs/SELF_HOSTING_CLOUDFLARE.md file, this secret can also be configured via the Cloudflare dashboard when self-hosting.
Choose Authentication Mode
OpenSEO supports three authentication modes controlled via the AUTH_MODE environment variable:
local_noauth– No auth checks; injects a trustedadmin@localhostidentity. This is automatically set when using the development scripts.cloudflare_access– Validates Cloudflare Access JWTs (cf-access-jwt-assertion). RequiresTEAM_DOMAINandPOLICY_AUDfor production-like testing.hosted– Better Auth email/password flow; requiresBETTER_AUTH_SECRETandBETTER_AUTH_URL.
To test Cloudflare Access locally, run:
AUTH_MODE=cloudflare_access pnpm dev
Run the Development Server
You have two options for running the local development server.
Option 1: Simple Vite dev server
pnpm run dev
This starts the worker at http://localhost:5173 but does not emulate Cloudflare’s routing model.
Option 2: Recommended portless workflow
mkdir -p .logs && touch .logs/dev-server.log
pnpm dev:agents
The portless tool proxies requests to http://open-seo.localhost:1355 and writes raw worker logs to .logs/dev-server.log. This mirrors the Cloudflare runtime, exposing the same environment bindings and hostnames used in production.
Switch to PostgreSQL (Optional)
If you prefer PostgreSQL over SQLite, or if you are testing scaling scenarios, you can run a local Postgres container.
Start the Docker 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 the Postgres migrations located under drizzle-pg/:
POSTGRES_DATABASE_URL=postgres://openseo:openseo@localhost:5433/openseo \
pnpm db:migrate:pg
Update .env.local to switch the provider:
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. To revert to D1, set DATABASE_PROVIDER=d1 and restart.
Common Development Commands
Here is a consolidated reference for the most frequent commands when developing OpenSEO:
# Install dependencies
pnpm install
# Initialize SQLite database
pnpm run db:migrate:local
# Copy environment template
cp .env.example .env.local
# Edit .env.local to add base64-encoded DATAFORSEO_API_KEY
# Start recommended dev server (with portless)
mkdir -p .logs && touch .logs/dev-server.log
pnpm dev:agents
# Test with Cloudflare Access auth
AUTH_MODE=cloudflare_access pnpm dev
# Start PostgreSQL locally (optional)
docker run --name openseo-postgres \
-e POSTGRES_USER=openseo \
-e POSTGRES_PASSWORD=openseo \
-e POSTGRES_DB=openseo \
-p 5433:5432 -d postgres:16
# Apply PostgreSQL migrations
POSTGRES_DATABASE_URL=postgres://openseo:openseo@localhost:5433/openseo \
pnpm db:migrate:pg
Summary
- Install prerequisites: Node 20+, pnpm, and optionally Docker.
- Initialize the database: Run
pnpm run db:migrate:localto create the SQLite schema fromsrc/db/. - Configure secrets: Copy
.env.exampleto.env.localand add your base64-encoded DataForSEO API key. - Start the server: Use
pnpm dev:agentsfor the most accurate Cloudflare runtime simulation via portless. - Switch backends: Set
DATABASE_PROVIDER=postgresand runpnpm db:migrate:pgafter starting a Docker PostgreSQL container on port 5433. - Test auth flows: Set
AUTH_MODEtocloudflare_accessorhostedwhen testing specific authentication requirements.
Frequently Asked Questions
What are the minimum system requirements for OpenSEO development?
You need Node 20 or higher and pnpm installed on your system. The default database is SQLite (via Cloudflare D1 compatibility), so no additional database software is required unless you choose to run PostgreSQL locally. If using PostgreSQL, Docker is required to run the containerized database.
How do I obtain and configure the DataForSEO API key?
You must have a DataForSEO account to get login credentials. According to the docs/LOCAL_DEVELOPMENT.md, you encode your login:password string using base64 (e.g., printf '%s' 'login:pass' | base64) and paste the result into the DATAFORSEO_API_KEY field of your .env.local file. This token is required for the application to fetch SEO data.
What is the difference between pnpm dev and pnpm dev:agents?
pnpm dev starts a standard Vite development server at http://localhost:5173 and automatically sets AUTH_MODE=local_noauth. pnpm dev:agents runs the worker through portless, which mimics Cloudflare’s routing model and proxies to http://open-seo.localhost:1355. The portless method is recommended because it provides environment bindings identical to production and logs output to .logs/dev-server.log for easier debugging.
Can I switch between SQLite and PostgreSQL without changing code?
Yes. The application uses a provider-agnostic DB layer in src/db/. To switch backends, set the DATABASE_PROVIDER environment variable to postgres or d1 in your .env.local file. For PostgreSQL, you must also run pnpm db:migrate:pg after setting the POSTGRES_DATABASE_URL. The Vite runtime automatically maps the HYPERDRIVE binding in wrangler.jsonc based on this configuration, requiring no code changes.
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 →