# How to Set Up Local Development with Wrangler and D1 Migrations in Open-SEO

> Learn to set up local development with Wrangler and D1 migrations for Open-SEO. Configure environment variables and run local migrations to start developing your agents efficiently.

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

---

**To configure local development with wrangler and D1 migrations in Open-SEO, enable Corepack for PNPM management, configure environment variables in `.env.local`, and execute `pnpm run db:migrate:local` to initialize the SQLite-backed Durable Object schemas before starting the development server with `pnpm dev:agents`.**

The every-app/open-seo repository runs on Cloudflare Workers and uses Wrangler to manage build processes, deployments, and database schema migrations. Setting up a local environment requires coordinating the PNPM package manager, environment configuration, and the D1 migration system that provisions SQLite-backed Durable Object tables.

## Prerequisites: Configure PNPM with Corepack

Before running any database commands, ensure your package manager matches the version declared in the repository. Open-SEO uses Corepack to enforce PNPM versioning through the `packageManager` field in [`package.json`](https://github.com/every-app/open-seo/blob/main/package.json).

Enable Corepack and install dependencies:

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

```

The `packageManager` field pins an exact PNPM version, ensuring that migration scripts and Wrangler commands execute in a reproducible environment across different development machines.

## Environment Configuration

Create a local environment file from the provided example. This stores sensitive credentials and runtime configuration required by both Wrangler and the application.

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

```

Edit `.env.local` to include your DataForSEO credentials and authentication mode:

```bash
DATAFORSEO_API_KEY=BASE64_LOGIN_PASSWORD
AUTH_MODE=local_noauth

```

Variables defined in `.env.local` are automatically loaded by Wrangler during local development and are referenced by the Miniflare instance when running `pnpm dev:agents`.

## Running D1 Migrations with Wrangler

Open-SEO uses dependency-injection style migrations—defined in `wrangler.jsonc`—to automatically provision SQLite tables for Durable Object classes. The `migrations` array in [`wrangler.jsonc`](https://github.com/every-app/open-seo/blob/main/wrangler.jsonc) lists migration tags (such as `v1`, `v2`, `v3`) that correspond to Durable Object classes like `OnboardingChatAgent`, `SamChatAgent`, and `AuditScratchpad`.

Execute the migrations to initialize your local database:

```bash
pnpm run db:migrate:local

```

This command processes the migration tags sequentially. Wrangler compares the stored migration state in `.wrangler/state/` against the highest tag defined in `wrangler.jsonc`, automatically creating the required SQLite tables for each new Durable Object class without requiring manual `CREATE TABLE` statements.

The migration system maintains schema synchronization between your code and the local SQLite database (D1), ensuring that Durable Object classes have their backing tables provisioned before the development server starts.

## Starting the Development Server

Once migrations complete, launch the local development environment. Open-SEO uses Miniflare in `portless` mode to simulate the Cloudflare Workers runtime.

Prepare the log directory and start the server:

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

```

The `pnpm dev:agents` command reads variables from `.env.local`, loads the migration state from the local SQLite database, and initializes the Durable Object classes. Logs are written to `.logs/dev-server.log` for debugging.

All database queries route through `src/db/`, which abstracts over the underlying storage provider. This abstraction layer allows the same application code to run against both the local D1 (SQLite) backend and the optional Postgres backend.

## Optional: Switching to Postgres for Local Development

For larger datasets or production parity, Open-SEO supports an optional Postgres backend via Hyperdrive. This requires Docker for running a local Postgres instance.

Start a Postgres container:

```bash
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 the database to accept connections:

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

```

Apply the Postgres-specific migrations located in `drizzle-pg/`:

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

```

Update `.env.local` to switch providers:

```bash
echo "DATABASE_PROVIDER=postgres" >> .env.local

```

Uncomment the `hyperdrive` block in `wrangler.jsonc` to enable the Postgres binding, then restart the development server with `pnpm dev`. The migration tags remain consistent between SQLite and Postgres schemas, ensuring data structure parity across providers.

## Summary

- **Enable Corepack** to use the exact PNPM version defined in [`package.json`](https://github.com/every-app/open-seo/blob/main/package.json) before installing dependencies.
- **Configure credentials** in `.env.local` copied from `.env.example`, including DataForSEO API keys and authentication mode.
- **Execute migrations** with `pnpm run db:migrate:local` to initialize D1 SQLite tables for Durable Object classes defined in `wrangler.jsonc`.
- **Start development** using `pnpm dev:agents`, which launches Miniflare and loads environment variables automatically.
- **Use Postgres optionally** by setting `DATABASE_PROVIDER=postgres`, running a Docker container, and executing `pnpm db:migrate:pg` with the appropriate connection string.

## Frequently Asked Questions

### How does the D1 migration system work in Wrangler?

The migration system relies on the `migrations` array in `wrangler.jsonc`. When you run `pnpm run db:migrate:local`, Wrangler checks the current migration tag stored in `.wrangler/state/` against the highest tag defined in the configuration. It then automatically provisions SQLite tables for any new Durable Object classes listed in the migration entries, eliminating the need for manual schema creation.

### Where are the Durable Object migration tags defined?

Migration tags are defined in the `migrations` field of [`wrangler.jsonc`](https://github.com/every-app/open-seo/blob/main/wrangler.jsonc). Each entry includes a tag (such as `v1` or `v2`) and a list of Durable Object class names. Wrangler uses these tags to track which schema versions have been applied to the local SQLite database.

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

Yes. Open-SEO supports a provider-agnostic database layer through `src/db/`. To use Postgres locally, start a Docker container running Postgres 16, set `DATABASE_PROVIDER=postgres` in `.env.local`, uncomment the `hyperdrive` block in `wrangler.jsonc`, and run `pnpm db:migrate:pg` with your connection string. The same migration tags are applied to keep Postgres schema synchronized with the D1 structure.

### What is the difference between `db:migrate:local` and `db:migrate:pg`?

`db:migrate:local` executes Wrangler-managed migrations for the default D1 SQLite backend, automatically creating tables for Durable Object classes based on `wrangler.jsonc`. `db:migrate:pg` applies hand-written SQL migration files from the `drizzle-pg/` directory to a Postgres instance, requiring a `POSTGRES_DATABASE_URL` environment variable.