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:

  1. Exact match "postgres" – Returns "postgres" to enable PostgreSQL mode
  2. "d1", undefined, or empty string – Falls back to "d1" for Cloudflare's SQLite offering
  3. 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:

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 getDatabaseProvider function in src/db/provider.ts determines the active database by inspecting env.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
  • getPostgresConnectionString handles connection string generation when PostgreSQL mode is active
  • Downstream files like src/db/index.ts and src/lib/auth.ts consume 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →