Quickback Docs

Cloudflare Template

Step-by-step guide to creating and deploying a Quickback project on Cloudflare Workers with D1.

The Cloudflare template creates a production-ready backend running on Cloudflare Workers with D1 (SQLite at the edge), KV storage, and Better Auth.

Create the Project

quickback create cloudflare my-app
cd my-app

Aliases: quickback create cf my-app

This scaffolds a project with:

my-app/
├── quickback/
│   ├── quickback.config.ts       # Compiler configuration
│   └── features/
│       └── todos/
│           ├── todos.ts          # Schema + security (defineTable)
│           └── actions.ts        # Custom actions
├── src/                          # Compiled output (generated)
├── drizzle/                      # Migrations (generated)
├── package.json
├── tsconfig.json
├── wrangler.toml
└── drizzle.config.ts

Generated Configuration

quickback.config.ts

import { defineConfig } from "@quickback/define";

export default defineConfig({
  name: "my-app",
  template: "hono",
  features: ["organizations"],
  providers: {
    runtime: { name: "cloudflare", config: {} },
    database: {
      name: "cloudflare-d1",
      config: { binding: "DB" },
    },
    auth: { name: "better-auth", config: {} },
  },
});

Example Feature (todos.ts)

The template includes a todos feature with all four security pillars configured:

import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
import { defineTable } from "@quickback/compiler";

export const todos = sqliteTable("todos", {
  id: text("id").primaryKey(),
  title: text("title").notNull(),
  description: text("description"),
  completed: integer("completed", { mode: "boolean" }).default(false),
  priority: text("priority").default("medium"),
  dueDate: integer("due_date", { mode: "timestamp" }),
  organizationId: text("organization_id").notNull(),
  ownerId: text("owner_id").notNull(),
});

export default defineTable(todos, {
  firewall: {
    organization: {},
    owner: { mode: "optional" },
    softDelete: {},
  },
  guards: {
    createable: ["title", "description", "completed", "priority", "dueDate"],
    updatable: ["title", "description", "completed", "priority", "dueDate"],
    immutable: ["id", "organizationId", "ownerId"],
  },
  masking: {
    description: {
      type: "redact",
      show: { roles: ["owner", "admin"] },
    },
  },
  crud: {
    list: { access: { roles: ["owner", "admin", "member"] } },
    get: { access: { roles: ["owner", "admin", "member"] } },
    create: { access: { roles: ["owner", "admin", "member"] } },
    update: { access: { roles: ["owner", "admin", "member"] } },
    delete: { access: { roles: ["owner", "admin"] }, mode: "soft" },
  },
});

Setup Steps

1. Install Dependencies

npm install

2. Log In to the Compiler

quickback login

3. Compile Your Definitions

quickback compile

This sends your definitions to the Quickback compiler and generates the full src/ directory, migrations, and configuration files.

4. Create D1 Databases

The Cloudflare template uses dual database mode by default — separate databases for auth and application data.

# Create the auth database
npx wrangler d1 create my-app-auth

# Create the features database
npx wrangler d1 create my-app-features

Copy the database IDs from the output and update your wrangler.toml:

[[d1_databases]]
binding = "AUTH_DB"
database_name = "my-app-auth"
database_id = "paste-auth-id-here"

[[d1_databases]]
binding = "DB"
database_name = "my-app-features"
database_id = "paste-features-id-here"

5. Run Migrations (Local)

npm run db:migrate:local

This applies migrations to both databases locally.

6. Start Development Server

npm run dev

Your API is running at http://localhost:8787.

Wrangler Configuration

The compiler generates a wrangler.toml with all required bindings:

name = "my-app"
main = "src/index.ts"
compatibility_date = "2025-03-01"
compatibility_flags = ["nodejs_compat"]

[observability]
enabled = true

[placement]
mode = "smart"

# Auth database
[[d1_databases]]
binding = "AUTH_DB"
database_name = "my-app-auth"
database_id = "your-auth-db-id"

# Features database
[[d1_databases]]
binding = "DB"
database_name = "my-app-features"
database_id = "your-features-db-id"

# Key-value storage
[[kv_namespaces]]
binding = "KV"
id = "your-kv-id"

Optional Bindings

Depending on your configuration, the compiler may also generate bindings for:

BindingTypeWhen Generated
R2_BUCKETR2 BucketfileStorage configured
AIWorkers AIembeddings configured on any feature
VECTORIZEVectorize Indexembeddings configured
EMBEDDINGS_QUEUEQueueembeddings configured
WEBHOOKS_DBD1Webhooks enabled
WEBHOOKS_QUEUEQueueWebhooks enabled
BROADCASTERServicerealtime configured

Dual Database Mode

By default, the Cloudflare template separates auth tables from application tables:

  • AUTH_DB — Better Auth tables (users, sessions, accounts, organizations, members)
  • DB — Your feature tables (todos, etc.)

This keeps auth data isolated and allows independent scaling. Each database gets its own migration directory:

drizzle/
├── auth/          # Auth migrations
│   ├── meta/
│   └── 0000_*.sql
└── features/      # Feature migrations
    ├── meta/
    └── 0000_*.sql

Deploying to Production

1. Apply Remote Migrations

npm run db:migrate:remote

2. Deploy to Cloudflare

npm run deploy

This runs wrangler deploy to push your worker to Cloudflare's edge network.

Available Scripts

ScriptCommandDescription
devwrangler devStart local dev server
deploynpm run db:migrate:remote && wrangler deployDeploy to production
db:migrate:localRuns auth + features migrations locallyApply migrations to local D1
db:migrate:remoteRuns auth + features migrations remotelyApply migrations to production D1

Next Steps

On this page