How the `getDatabaseProvider` Function Works in OpenSEO: Database Backend Selection
The getDatabaseProvider function in OpenSEO reads the DATABASE_PROVIDER environment variable to determine whether to use PostgreSQL via Hyperdrive or Cloudflare D1, returning "postgres" or "d1" respectively while throwing an error for unsupported configurations.
OpenSEO is an open-source SEO management platform built for Cloudflare Workers. The getDatabaseProvider function serves as the single source of truth for database backend selection, allowing the application to switch seamlessly between PostgreSQL and Cloudflare's D1 SQLite without hardcoding environment checks throughout the codebase.
Where getDatabaseProvider is Implemented
Source Location and Imports
The function lives in src/db/provider.ts. It imports the Cloudflare Workers runtime environment to access configuration variables securely.
import { env } from "cloudflare:workers";
export function getDatabaseProvider(): "postgres" | "d1" {
const provider = Reflect.get(env, "DATABASE_PROVIDER");
if (provider === "postgres") return "postgres";
if (provider === "d1" || provider === undefined || provider === "") {
return "d1";
}
throw new Error(`Unsupported DATABASE_PROVIDER: ${provider}`);
}
The Decision Logic
The function uses Reflect.get(env, "DATABASE_PROVIDER") to retrieve the configuration value. This approach safely accesses the binding without assuming its existence at compile time. The logic follows a strict priority:
- Exact match
"postgres"– Returns"postgres"to enable PostgreSQL mode "d1",undefined, or empty string – Falls back to"d1"for Cloudflare's SQLite offering- Any other value – Throws a descriptive error to prevent startup with invalid configurations
How Database Selection Works at Runtime
Reading the Cloudflare Workers Environment
OpenSEO runs on Cloudflare Workers, where environment variables and bindings are injected via the env object. The getDatabaseProvider function accesses this runtime context directly through the cloudflare:workers module import. You can set DATABASE_PROVIDER in your wrangler.toml configuration or via a .env file during local development.
Supported Database Providers
The function explicitly supports two backends:
"postgres"– Triggers PostgreSQL connectivity through the Hyperdrive binding, suitable for high-performance production workloads"d1"– Activates Cloudflare's distributed SQLite database, ideal for edge-deployed applications with lower latency requirements
If the variable is omitted entirely, the function defaults to "d1" to ensure out-of-the-box functionality with Cloudflare's native infrastructure.
Error Handling for Invalid Configurations
Unlike silent defaults that might mask typos, getDatabaseProvider validates inputs strictly. Setting DATABASE_PROVIDER="mysql" or any unsupported string immediately throws an exception with the message Unsupported DATABASE_PROVIDER: [value], preventing runtime ambiguity.
Helper Function: getPostgresConnectionString
When the provider resolves to "postgres", the companion function getPostgresConnectionString constructs the connection string from the HYPERDRIVE binding. This separation of concerns keeps provider detection independent from connection management.
import { getPostgresConnectionString } from "@/db/provider";
const connectionString = getPostgresConnectionString();
const pool = new Pool({ connectionString });
The Hyperdrive binding automatically handles connection pooling and latency optimization between your Worker and the PostgreSQL instance.
Usage Examples in OpenSEO
Branching Database Logic in Services
Application services call getDatabaseProvider() to execute database-specific queries without importing environment details:
import { getDatabaseProvider } from "@/db/provider";
if (getDatabaseProvider() === "postgres") {
await pgClient.query('SELECT * FROM seo_data WHERE url = $1', [url]);
} else {
await d1DB.prepare('SELECT * FROM seo_data WHERE url = ?').bind(url).run();
}
Configuring Telemetry Backends
The telemetry system uses the provider to tag metrics correctly:
import { getDatabaseProvider } from "@/db/provider";
const telemetryDeps = {
getDbBackend: getDatabaseProvider,
// ... other dependencies
};
Integration Across the Codebase
The getDatabaseProvider function integrates into multiple critical paths:
src/db/index.ts– Instantiates the correctdbobject based on the provider valuesrc/lib/auth.ts– Adjusts authentication queries for PostgreSQL syntax versus D1 constraintssrc/db/runBatch.ts– Executes batch operations using provider-specific transaction handlingsrc/server/lib/self-host-telemetry.ts– Reports which backend is active for monitoring purposes
This centralized architecture ensures that adding a third database backend requires changes only in src/db/provider.ts and the database initialization layer.
Summary
- The
getDatabaseProviderfunction insrc/db/provider.tsdetermines the active database by inspectingenv.DATABASE_PROVIDER - It returns
"postgres"for PostgreSQL via Hyperdrive or"d1"(the default) for Cloudflare's SQLite - Invalid values trigger immediate exceptions to prevent misconfiguration
getPostgresConnectionStringhandles connection string generation when PostgreSQL mode is active- Downstream files like
src/db/index.tsandsrc/lib/auth.tsconsume this function to maintain environment-agnostic business logic
Frequently Asked Questions
What happens if DATABASE_PROVIDER is not set?
If the variable is undefined or empty, getDatabaseProvider defaults to returning "d1", enabling the application to run immediately on Cloudflare's D1 infrastructure without explicit configuration.
Can I use a database other than PostgreSQL or D1?
No. The function explicitly validates the provider value and throws an error for any unsupported database. To add support for another backend like MySQL, you must modify src/db/provider.ts to recognize the new provider string and update all-consuming services to handle the new connection type.
How does getPostgresConnectionString work with Hyperdrive?
The function accesses the HYPERDRIVE binding from the Cloudflare Workers environment, which contains pre-configured connection details for your PostgreSQL instance. It returns a formatted connection string that Node.js PostgreSQL clients like pg can consume directly, with Hyperdrive managing connection pooling and latency optimization automatically.
Where should I configure DATABASE_PROVIDER in a Cloudflare Workers environment?
Set the variable in your wrangler.toml file under [vars] for production deployments, or create a .env file in your project root for local development with wrangler dev. The Cloudflare Workers runtime injects these values into the env object at runtime.
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 →