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.

cloudflare is a bare scaffold — multi-tenant orgs + auth + DB are wired in, but there are no example features. Add your own feature files under quickback/features/. If you want a working example to read first, use the todos template — same providers, but with a complete todos feature ready to extend.

Create the Project

The fastest path is start — interactive, scaffold + login + compile in one flow:

mkdir my-app && cd my-app
npx @quickback-dev/cli start
# pick "Cloudflare (bare scaffold)" at the prompt

Scriptable equivalent:

quickback create cloudflare my-app    # aliases: cf
cd my-app

This scaffolds a project with:

my-app/
├── quickback/
│   ├── quickback.config.ts       # Compiler configuration
│   └── features/                  # (empty — add your own)
├── src/                          # Compiled output (generated by `quickback compile`)
├── package.json
├── tsconfig.json
├── wrangler.toml
└── drizzle.config.ts

Generated Configuration

quickback.config.ts

export default {
  name: "my-app",
  template: "hono",
  features: {
    organizations: true,
  },
  auth: {
    // Use "role+" in access rules to mean "this role and above".
    // e.g. roles: ["member+"] expands to ["member", "admin", "owner"].
    roleHierarchy: ["member", "admin", "owner"],
  },
  providers: {
    runtime: { name: "cloudflare", config: {} },
    database: {
      name: "cloudflare-d1",
      config: { binding: "DB", realtime: true },
    },
    auth: { name: "better-auth", config: {} },
  },
};

Adding your first feature

Create a file at quickback/features/<name>/<name>.ts and export a defineTable(...) default. The shape used by the todos template makes a good starting point — see todos.ts in the template registry for a full multi-tenant example with masking, actions, and a named view.

// quickback/features/posts/posts.ts
import { sqliteTable, text } from "drizzle-orm/sqlite-core";
import { defineTable } from "@quickback/compiler";

export const posts = sqliteTable("posts", {
  id: text("id").primaryKey(),
  title: text("title").notNull(),
  body: text("body"),
  organizationId: text("organization_id").notNull(),
  userId: text("user_id").notNull(),
});

export default defineTable(posts, {
  firewall: { organization: {}, owner: {}, softDelete: {} },
  guards: {
    createable: ["title", "body"],
    updatable: ["title", "body"],
    immutable: ["id", "organizationId", "userId"],
  },
  read: { access: { roles: ["member+"] } },
  create: { access: { roles: ["member+"] } },
  update: { access: { roles: ["member+"] } },
  delete: { access: { roles: ["admin+"] }, mode: "soft" },
});

Setup Steps

If you used quickback start, dependencies, the first compile, and login are already done — skip to step 4. If you used quickback create, run these:

1. Install Dependencies

npm install

2. Compile Your Definitions

quickback compile

This prompts for an account on the first run (sign in or create one in the browser), then generates the full src/ directory, migrations, and configuration files. Subsequent compiles re-use the stored session.

3. 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"

4. Run Migrations (Local)

npm run db:migrate:local

This applies migrations to both databases locally.

5. 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:

quickback/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