How to Set Up Local Development with Wrangler and D1 Migrations in Open-SEO
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.
Enable Corepack and install dependencies:
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.
cp .env.example .env.local
Edit .env.local to include your DataForSEO credentials and authentication mode:
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 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:
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:
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:
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:
docker exec openseo-postgres pg_isready -U openseo -d openseo
Apply the Postgres-specific migrations located in drizzle-pg/:
POSTGRES_DATABASE_URL=postgres://openseo:openseo@localhost:5433/openseo \
pnpm db:migrate:pg
Update .env.local to switch providers:
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.jsonbefore installing dependencies. - Configure credentials in
.env.localcopied from.env.example, including DataForSEO API keys and authentication mode. - Execute migrations with
pnpm run db:migrate:localto initialize D1 SQLite tables for Durable Object classes defined inwrangler.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 executingpnpm db:migrate:pgwith 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. 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.
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 →