How to Configure OpenSEO for D1/SQLite Database: 5-Step Setup Guide
Set DATABASE_PROVIDER=d1 (or leave it unset), run pnpm run db:migrate:local, and start the dev server to run OpenSEO on Cloudflare D1 (SQLite) — no PostgreSQL required.
OpenSEO is an open-source SEO management platform built for Cloudflare Workers that supports two data stores: Cloudflare D1 (SQLite) and PostgreSQL. The D1/SQLite configuration is the default and simplest way to get started, whether you're running locally or deploying to production. This guide walks through the exact configuration steps based on the OpenSEO source code, with references to specific files and implementation details.
Set the Database Provider in Environment Variables
OpenSEO detects your database backend through the DATABASE_PROVIDER environment variable. For D1/SQLite, you have two options:
- Recommended: Omit
DATABASE_PROVIDERentirely — D1 is the default - Explicit: Set
DATABASE_PROVIDER=d1in your.env.localorwrangler.toml
The provider detection logic lives in src/db/provider.ts. This file exports getDatabaseProvider(), which returns "d1" or "postgres" and determines which driver and schema set the application loads.
# .env.local
DATABASE_PROVIDER=d1
AUTH_MODE=local_noauth
With AUTH_MODE=local_noauth, you bypass BetterAuth for local development — this mode works seamlessly with the D1 store without additional authentication configuration.
Verify the SQLite Schema Files
When DATABASE_PROVIDER resolves to "d1", OpenSEO automatically loads the SQLite schema files located in src/db/*.schema.ts. Key files include:
src/db/app.schema.ts— Core application tables- Other
*.schema.tsfiles insrc/db/— Feature-specific table definitions
These files define the Drizzle ORM schema used when the provider is SQLite. No manual configuration is required; the schema is imported automatically based on the provider selection.
Run D1 Database Migrations
Once your environment variables are set, create the local D1 database by running the migration command:
pnpm run db:migrate:local
This executes Drizzle migration scripts against the SQLite file bound to your local Worker environment. The migration creates all necessary tables according to the SQLite schema definitions.
After the initial migration, subsequent schema changes are handled through Drizzle's migration system — run the same command to apply updates.
Start the Development Server
With migrations complete, launch the development server using one of these commands:
# Standard development server
pnpm run dev
# Agents-friendly server (recommended for most setups)
pnpm dev:agents
The dev:agents variant is optimized for development environments using agent-based workflows and is the recommended approach in the LOCAL_DEVELOPMENT.md documentation.
How the D1 Database Adapter Works
The actual database connection and Drizzle adapter creation happens in src/lib/auth.ts. Here's the implementation that switches between PostgreSQL and SQLite:
const database =
getDatabaseProvider() === "postgres"
? drizzleAdapter(pgDb, { provider: "pg", schema: pgSchema })
: drizzleAdapter(d1Db, { provider: "sqlite", schema: d1Schema });
When getDatabaseProvider() returns "d1" (the default), the code:
- Uses
d1Db— the D1 database binding passed through the execution context - Sets
provider: "sqlite"— tells Drizzle to use SQLite dialect - Loads
d1Schema— the SQLite-specific schema definitions fromsrc/db/*.schema.ts
This architecture allows OpenSEO to maintain dual database support with a single codebase. The conditional logic in src/lib/auth.ts and src/db/provider.ts handles the abstraction, so your application code remains provider-agnostic.
Optional: Switch to PostgreSQL Later
If you need to migrate from D1 to PostgreSQL in the future, change a single environment variable:
DATABASE_PROVIDER=postgres
You'll also need to provide a Hyperdrive binding or local connection string for PostgreSQL. The same adapter code in src/lib/auth.ts automatically switches to the Postgres Drizzle adapter when the provider changes — no other code modifications required.
Summary
- D1 is the default: Leave
DATABASE_PROVIDERunset or explicitly set it to"d1"to use SQLite - Three key files control the setup:
src/db/provider.ts(detection),src/lib/auth.ts(adapter creation), andsrc/db/*.schema.ts(table definitions) - Two commands to start:
pnpm run db:migrate:localthenpnpm dev:agents - Auth mode matters: Use
AUTH_MODE=local_noauthfor frictionless local D1 development - Future-proof: One environment variable change switches the entire stack to PostgreSQL
Frequently Asked Questions
What is the default database provider in OpenSEO?
D1 (SQLite) is the default database provider. If you don't set DATABASE_PROVIDER, getDatabaseProvider() in src/db/provider.ts returns "d1" and the application initializes with SQLite bindings. This design prioritizes the simplest local development experience and aligns with Cloudflare's edge-native architecture.
Can I use OpenSEO with D1 without any authentication setup?
Yes. Set AUTH_MODE=local_noauth in your environment variables. This mode bypasses the BetterAuth integration entirely and allows you to interact with the D1 database without configuring OAuth providers, sessions, or user management. It's the recommended approach for initial local development.
Where does the actual database connection happen in the OpenSEO codebase?
The database adapter is instantiated in src/lib/auth.ts using Drizzle's adapter pattern. The code evaluates getDatabaseProvider() and creates either a PostgreSQL adapter (provider: "pg") or SQLite adapter (provider: "sqlite"). The d1Db binding comes from the Cloudflare Workers environment, injected at runtime through Wrangler's local dev server or production deployment.
Is there any performance difference between D1 and PostgreSQL in OpenSEO?
For typical SEO management workloads — crawling, indexing status tracking, and metadata storage — D1 performs well within Cloudflare's edge network. The same Drizzle ORM queries execute against both backends. PostgreSQL becomes advantageous for complex analytical queries, high-volume concurrent writes, or when you need specific Postgres extensions. The abstraction in OpenSEO allows you to start with D1 and migrate to PostgreSQL without rewriting application code.
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 →