# How to Set Up OpenSEO for Local Development: A Complete Guide

> Learn how to set up OpenSEO for local development with our comprehensive guide. Follow simple steps to install dependencies, initialize the database, configure API keys, and launch your dev server.

- Repository: [Every App/open-seo](https://github.com/every-app/open-seo)
- Tags: how-to-guide
- Published: 2026-08-30

---

**To set up OpenSEO for local development, enable Corepack for pnpm, install dependencies with `pnpm install --frozen-lockfile`, initialize the database with `pnpm run db:migrate:local`, configure your base64-encoded DataForSEO API key in `.env.local`, and launch the dev server using `pnpm dev:agents`.**

OpenSEO is a full-stack TypeScript application developed by every-app that combines TanStack server functions, a custom MCP (Managed-Content-Provider) API for AI agents, and a flexible data layer supporting Cloudflare D1 (SQLite) or Postgres. Setting up OpenSEO for local development requires configuring the database layer, selecting an authentication mode, and initializing the DataForSEO API integration before starting the development server.

## Prerequisites and Repository Setup

Begin by enabling the exact pnpm version declared in the project's [`package.json`](https://github.com/every-app/open-seo/blob/main/package.json) using Corepack. This ensures consistent package management across all development environments.

```bash
corepack enable
pnpm install --frozen-lockfile

```

The `--frozen-lockfile` flag guarantees reproducible installs by preventing automatic lockfile updates during dependency resolution.

## Database Configuration and Migrations

OpenSEO uses **Drizzle ORM** for database management with **Cloudflare D1 (SQLite)** as the default data layer. For larger installations, you can switch to Postgres by using the alternate configuration file.

Run the migration script to initialize your local database schema:

```bash
pnpm run db:migrate:local

```

This command executes migrations defined in [`drizzle.config.ts`](https://github.com/every-app/open-seo/blob/main/drizzle.config.ts) for SQLite or [`drizzle-pg.config.ts`](https://github.com/every-app/open-seo/blob/main/drizzle-pg.config.ts) for Postgres environments. The migration system creates the necessary tables for workflows, site audits, and rank checking functionality. For example data seeding, reference [`scripts/seed-projects.ts`](https://github.com/every-app/open-seo/blob/main/scripts/seed-projects.ts) in the repository.

To generate new migration files after modifying the Drizzle schema:

```bash
pnpm run db:generate

```

## Environment Configuration and API Keys

Copy the example environment file and configure your local settings:

```bash
cp .env.example .env.local

```

You must provide a **DataForSEO API key** encoded as base64 `login:password`. Generate the encoded string using:

```bash
printf '%s' 'your_login:your_password' | base64

```

Place the resulting output into the `DATAFORSEO_API_KEY` variable in `.env.local`. Consult [`docs/DATAFORSEO_API_KEY.md`](https://github.com/every-app/open-seo/blob/main/docs/DATAFORSEO_API_KEY.md) for detailed instructions on obtaining these credentials.

## Authentication Modes for Local Development

OpenSEO supports three authentication modes configured via the `AUTH_MODE` environment variable in `.env.local`, as implemented in [`src/lib/auth.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/auth.ts):

- **`local_noauth`** – Injects a fake admin user (`admin@localhost`) for frictionless local development without external identity providers.
- **`cloudflare_access`** – Validates Cloudflare Access JWT tokens for environments protected by Cloudflare's Zero Trust network.
- **`hosted`** – Activates Better Auth for full email/password authentication flows, requiring additional `BETTER_AUTH_*` environment variables.

For local development, set `AUTH_MODE=local_noauth` to bypass authentication checks entirely.

## Starting the Development Server

OpenSEO provides two development server modes depending on your debugging requirements.

### Standard Development Mode

Run the following command to start the UI development server:

```bash
pnpm run dev

```

This serves the application at `http://localhost:5173` using the standard Vite development server configuration defined in the project setup.

### Agent-Friendly Development Mode

For debugging AI agent interactions and MCP (Managed-Content-Provider) functionality, use the portless development mode:

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

```

This command starts the application via **portless** at `http://open-seo.localhost:1355` and streams logs to `.logs/dev-server.log`. If you are working within a Git worktree, the URL automatically prefixes with your branch name (e.g., `http://feature-x.open-seo.localhost:1355`).

The development server bootstraps through [`src/start.ts`](https://github.com/every-app/open-seo/blob/main/src/start.ts), which configures TanStack server functions and routing, while [`src/server.ts`](https://github.com/every-app/open-seo/blob/main/src/server.ts) serves as the main Cloudflare Worker entry point that wires up the MCP implementation from `src/server/mcp/*` and workflow handlers.

## Workflow Development and MCP Integration

With your local environment running, you can extend OpenSEO's functionality by modifying:

- **Server Workflows** – Located in `src/server/workflows/`, including [`SiteAuditWorkflow.ts`](https://github.com/every-app/open-seo/blob/main/SiteAuditWorkflow.ts) for site audit orchestration.
- **MCP Handlers** – Located in `src/server/mcp/`, providing the API surface that AI agents interact with.

Changes to these files trigger hot reloading in the development server, allowing immediate testing of backend logic and AI agent integrations.

## Summary

- Enable **Corepack** and use `pnpm install --frozen-lockfile` to ensure consistent dependency versions across environments.
- Initialize the database layer with `pnpm run db:migrate:local`, supporting either D1 (SQLite) via [`drizzle.config.ts`](https://github.com/every-app/open-seo/blob/main/drizzle.config.ts) or Postgres via [`drizzle-pg.config.ts`](https://github.com/every-app/open-seo/blob/main/drizzle-pg.config.ts).
- Configure `DATAFORSEO_API_KEY` as a base64-encoded string in `.env.local` to enable SEO data fetching capabilities.
- Set `AUTH_MODE=local_noauth` for streamlined local development without external authentication providers.
- Launch the development server with `pnpm dev:agents` to access the portless URL at `http://open-seo.localhost:1355` with dedicated logging support.

## Frequently Asked Questions

### What is the difference between `pnpm dev` and `pnpm dev:agents`?

`pnpm run dev` starts a standard Vite development server on port 5173 for UI development, while `pnpm dev:agents` launches a portless server at `http://open-seo.localhost:1355` specifically designed for AI agent development. The agent mode streams detailed logs to `.logs/dev-server.log` and supports Git worktree URL prefixes for branch-specific testing.

### How do I configure the DataForSEO API key for local development?

You must encode your DataForSEO credentials as a base64 string in the format `login:password` and place it in the `DATAFORSEO_API_KEY` environment variable within `.env.local`. Use the command `printf '%s' 'login:password' | base64` to generate the correct format, then restart your development server to apply the changes.

### Can I use Postgres instead of SQLite for local development?

Yes. While OpenSEO defaults to Cloudflare D1 (SQLite), you can switch to Postgres by utilizing the [`drizzle-pg.config.ts`](https://github.com/every-app/open-seo/blob/main/drizzle-pg.config.ts) configuration file and ensuring your environment variables point to a Postgres instance. Run `pnpm run db:migrate:local` after switching configurations to apply the schema to your Postgres database.

### How do I disable authentication for local testing?

Set `AUTH_MODE=local_noauth` in your `.env.local` file. This mode, handled by [`src/lib/auth.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/auth.ts), injects a fake admin user (`admin@localhost`) into the request context, allowing full access to all application features without configuring Cloudflare Access or Better Auth credentials.