Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/iterate/sqlfu/llms.txt

Use this file to discover all available pages before exploring further.

sqlfu/cloudflare ships helpers for every Alchemy and D1 configuration. The right helper depends on whether you are using Alchemy v1 local development (which persists a Miniflare SQLite file on disk) or Alchemy v2 (which connects to real cloud D1 resources during development).

Alchemy v1 vs v2

Alchemy v1 localAlchemy v2
Local dev databaseMiniflare SQLite file on diskReal Cloudflare D1 over HTTP
sqlfu helperfindMiniflareD1PathcreateAlchemyD1Client
State file.alchemy/miniflare/v3/.alchemy/state/<stack>/<stage>/
Alchemy v2 deliberately removed local D1 emulation. There is no Miniflare file to find — alchemy dev provisions a real cloud D1 resource, so sqlfu must talk to it over HTTP.

Alchemy v2: deployed D1

If your alchemy.run.ts declares a Cloudflare.D1Database("database") resource, createAlchemyD1Client reads alchemy’s local state and produces a sqlfu db factory:
sqlfu.config.ts
import {defineConfig} from 'sqlfu';
import {createAlchemyD1Client} from 'sqlfu/cloudflare';

export default defineConfig({
  db: () => createAlchemyD1Client({
    stack: 'my-app',
    stage: 'dev',
    fqn: 'database',
  }),
  migrations: {path: './migrations', preset: 'd1'},
  definitions: './definitions.sql',
  queries: './sql',
});
apiToken defaults to process.env.CLOUDFLARE_API_TOKEN. accountId and databaseId come from .alchemy/state/<stack>/<stage>/<fqn>.json — no UUID copy-paste required.

The state file

The state file is at .alchemy/state/<stack>/<stage>/<encoded-fqn>.json. readAlchemyD1State (the lower-level helper that createAlchemyD1Client calls internally) walks up from the current working directory until it finds an .alchemy/state/ directory, so it works from any subdirectory of your project. Pass {alchemyDir: '/abs/path/to/.alchemy'} to override when your config runs outside the project tree.

The fqn parameter

fqn is the resource’s fully-qualified name inside the alchemy app:
  • For a top-level Cloudflare.D1Database("database"), the fqn is "database".
  • For a D1Database("database") nested inside Namespace("Auth").run(...), the fqn is "Auth/database".

Using readAlchemyD1State directly

If you need more control — a different API token source, caching, or logging — use readAlchemyD1State and createD1HttpClient directly:
sqlfu.config.ts
import {defineConfig} from 'sqlfu';
import {createD1HttpClient, readAlchemyD1State} from 'sqlfu/cloudflare';

export default defineConfig({
  db: () => {
    const {accountId, databaseId} = readAlchemyD1State({
      stack: 'my-app',
      stage: 'dev',
      fqn: 'database',
    });

    return {
      client: createD1HttpClient({
        accountId,
        databaseId,
        apiToken: process.env.CLOUDFLARE_API_TOKEN!,
      }),
    };
  },
  migrations: {path: './migrations', preset: 'd1'},
});

Alchemy v1: local Miniflare D1

If your local development setup still writes a Miniflare D1 SQLite file (Alchemy v1 layout), use findMiniflareD1Path:
sqlfu.config.ts
import {defineConfig} from 'sqlfu';
import {findMiniflareD1Path} from 'sqlfu/cloudflare';

export default defineConfig({
  db: findMiniflareD1Path('my-dev-app-slug'),
  migrations: {path: './src/server/db/migrations', preset: 'd1'},
  definitions: './src/server/db/definitions.sql',
  queries: './src/server/db/queries',
});
findMiniflareD1Path('slug') walks up from process.cwd() until it finds .alchemy/miniflare/v3, then derives the D1 SQLite filename from the alchemy app slug. If your config runs outside the project tree, pass {miniflareV3Root: '/absolute/path/to/.alchemy/miniflare/v3'} as the second argument.
For Alchemy v2, prefer createAlchemyD1Client — there may be no local Miniflare file to find.

No alchemy: resolve by name

If you are not using Alchemy, or want to avoid reading alchemy’s state files, resolve D1 by database name:
sqlfu.config.ts
import {defineConfig} from 'sqlfu';
import {createD1HttpClient, findCloudflareD1ByName} from 'sqlfu/cloudflare';

export default defineConfig({
  db: async () => {
    const accountId = process.env.CLOUDFLARE_ACCOUNT_ID!;
    const apiToken = process.env.CLOUDFLARE_API_TOKEN!;
    const {databaseId} = await findCloudflareD1ByName({
      accountId,
      apiToken,
      name: 'my-app-dev-database',
    });

    return {client: createD1HttpClient({accountId, apiToken, databaseId})};
  },
  migrations: {path: './migrations', preset: 'd1'},
});
findCloudflareD1ByName uses GET /accounts/{id}/d1/database?name=... and throws if zero or multiple databases match. If you already have a databaseId, skip the lookup and pass it directly to createD1HttpClient.
This is also the right pattern when one config serves multiple environments by reading process.env.STAGE to pick the database name.

Cloudflare D1 guide

Full D1 project setup including Worker runtime code and query generation.

Durable Objects

Per-instance SQLite with synchronous migrations at startup.

Build docs developers (and LLMs) love