Short answer, SQLite semantics without managing a server #
Cloudflare D1 is SQLite compatible database storage used by BYOB apps that need persistence. Cloudflare documents D1 as its serverless SQL database with SQLite compatibility and edge placement (https://developers.cloudflare.com/d1/). If your task list, user accounts, or form data should still exist after a page refresh, it needs to live in a database rather than browser memory alone. D1 provides that persistent layer for edge runtimes.
BYOB pairs D1 with Better Auth for secure edge ready authentication. When you initialize auth in a BYOB project, the necessary D1 migrations run automatically. You focus on features, while BYOB handles the wiring between auth tables, Drizzle, and D1.
A database is the notebook that remembers what your users did after they leave the room. Browser memory forgets on refresh. D1 remembers.
Try it: JSON Formatter — so you can try this on your own site now.
What is D1? #
D1 is best understood as SQLite compatible storage for apps running on edge infrastructure. SQLite semantics mean familiar tables, rows, and queries, combined with a managed runtime so you never set up or operate a traditional database server yourself. Cloudflare's build with D1 guide walks the practical side: creating databases, binding them to workers, and querying from application code (https://developers.cloudflare.com/d1/build-with-d1/).
In BYOB, D1 is the natural answer to the prompt used when an app outgrows temporary state: connect the app to a database so records save permanently instead of only in browser memory. That one decision turns a demo that resets on refresh into software people can return to.
For background on the underlying platform, the official Cloudflare D1 docs are the source of truth for behavior beyond what BYOB wires automatically (https://developers.cloudflare.com/d1/).
-- The shape of early app data: small tables, clear owners
CREATE TABLE tasks (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
title TEXT NOT NULL,
done INTEGER NOT NULL DEFAULT 0,
created_at INTEGER NOT NULL
);| Option | Fit | Tradeoff | When to choose |
|---|---|---|---|
| D1 edge SQLite | Small apps with users and saved rows | Simpler relational power | Landing plus accounts plus user owned lists |
| Supabase Postgres | Linked tables with ownership rules | More setup and policy work | You need relational depth and RLS |
| Export and host elsewhere | Full infra control | You own ops | Compliance or custom architecture demands it |
| Browser memory only | Demo with no persistence | Refresh wipes data | Throwaway prototype |
Why do SQLite semantics matter? #
SQLite semantics help small apps because most early apps need the same simple patterns. Users sign up and log in. Sessions keep them signed in. Application records such as tasks, posts, profiles, or orders get created, listed, updated, and removed.
That simplicity is an advantage. You get structured persistence without introducing a separate complex backend at the start. It fits the way BYOB apps get built: start with a landing page or simple web application, refine through chat with live preview, then add accounts and saved data when the idea proves useful.
SQLite semantics also match the iterative BYOB workflow. Ask for user authentication so each visitor sees only their own tasks, then ask for persistence so those tasks remain after refresh. Each request builds on the same understandable table model rather than requiring a rewrite.
Cloudflare's best practices page adds the operational side: keep queries lean, batch sensibly, and understand how reads and writes flow at the edge (https://developers.cloudflare.com/d1/best-practices/). Small apps that follow those habits rarely think about the database at all. That is the goal.
How do schema, Drizzle, and migrations connect in BYOB? #
Connect auth to Cloudflare D1 in BYOB in 3 steps: declare the Better Auth schema for users, sessions, and accounts, map it through the Drizzle sqlite-proxy adapter, and let BYOB run the D1 migrations automatically. Prerequisite: a BYOB project with auth initialized. Constraint: standard ORM setups often struggle with edge compatibility, so never hand-write the adapter or sequence migrations by hand.
Connecting auth to D1 on edge runtimes requires specific patterns. Standard ORM setups often struggle with edge compatibility, so BYOB implements an adapter over the sqlite proxy shape for Drizzle. Drizzle documents itself as a TypeScript ORM with a SQL like query layer (https://drizzle.team/docs), and Better Auth documents adapters as the bridge between its schema and your database (https://www.better-auth.com/docs).
In practice the Better Auth schema for users, sessions, and accounts maps cleanly to the row structure D1 expects. You never hand write that glue code. When auth initializes, BYOB runs the required D1 migrations automatically and leaves working tables for identity and sessions.
// Drizzle schema sketch: users own their rows
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core';
export const tasks = sqliteTable('tasks', {
id: text('id').primaryKey(),
userId: text('user_id').notNull(),
title: text('title').notNull(),
done: integer('done').notNull().default(0)
});This wiring also avoids the multi domain OAuth trap that affects preview deployments. BYOB generated SvelteKit code parses forwarded host headers in the auth API route before passing the request to the Better Auth handler. OAuth redirect URIs and magic link verify URLs resolve correctly whether you test locally, on a preview URL, or in production.
The same principle applies beyond auth. Once D1 connects, feature prompts can assume persistence exists. Ask for due dates, saved preferences, or user specific lists, and the implementation has somewhere durable to store them.
Saving your project is still separate from saving app data. Use the Save button with descriptive messages to snapshot your project code, while D1 stores the runtime data your users create.
When should you graduate beyond D1? #
D1 fits the front end plus simple persistence stage that most BYOB apps start in: landing pages, marketing sites, portfolios, and simple web applications with accounts and saved records.
Graduate when the app needs complex backend functionality that no longer fits that pattern. Useful signals are workflows spanning many related data types, background processing, advanced access rules, or infrastructure decisions requiring direct database ownership. Cloudflare's best practices help you read those signals in your own query patterns (https://developers.cloudflare.com/d1/best-practices/).
BYOB gives two honest exits.
First, export and continue. The sites BYOB generates are real SvelteKit projects. If you outgrow the platform or need custom backend work, export the code and continue development in any standard development environment.
Second, choose a distinct managed path when your project explicitly needs it. If your project uses Supabase, BYOB supports Supabase Storage alongside Supabase Postgres with the appropriate client and policy patterns instead of Worker bindings. The two paths are distinct, so choose one from your database and infrastructure decision.
Until then, keep it simple. Use D1 for users, sessions, and saved app data. Refine through the preview. Publish with one click deploy when ready, then republish to the same URL as the app improves. Let graduation be driven by real product needs, not premature architecture.
Who this is for (and who should skip it) #
Cloudflare D1 through BYOB fits small apps where users, sessions, and saved records live in simple tables and you want persistence without running a server. Skip it when data needs linked tables with complex access rules or direct database ownership for compliance; choose a managed Postgres path or exported codebase instead.
This fits if you build small apps where users, sessions, and saved records live in simple tables and you want persistence without running a server. If your flow is landing page plus accounts plus user owned rows, D1 through Drizzle keeps things lean.
Skip it if your data needs linked tables with complex access rules, heavy relational joins, or direct database ownership for compliance. In those cases a managed Postgres path or an exported codebase gives more room.
- Best for developers adding persistent tables and queries to edge apps without running a server.
- Best for startups moving from browser memory to shared records with Drizzle and migrations.
- Best for freelancers wiring small client apps where SQLite semantics fit the data shape.
What we learned building this #
We wire BYOB persistence through Cloudflare D1 with a familiar table model, and we surface it in the product through a built-in database viewer. Auth tables for users, sessions, and accounts are set up automatically so the app can store user rows without hand-written glue code. In the project dashboard the database viewer sits alongside chat, so prompts that add auth or saved records have a durable place to land.