D1 Database Fundamentals
Before diving into migrations, let’s understand the database we’re working with. Cloudflare D1 is a serverless SQLite database that runs at the edge, and knowing its architecture helps you make better decisions throughout your project.
What is D1?
Cloudflare D1 is a serverless, edge-native SQL database built on SQLite. It’s designed to work seamlessly with Cloudflare Workers, providing low-latency data access from anywhere in the world.
Key Characteristics
- SQLite-based: D1 uses SQLite under the hood, giving you a familiar SQL dialect with a proven track record
- Serverless: No database servers to manage, scale, or maintain
- Edge-native: Your database runs close to your users, reducing latency
- Zero cold starts: D1 is always ready to serve requests
- Integrated with Workers: Native binding to Cloudflare Workers with zero configuration
When to Use D1
D1 is an excellent choice when you need:
- Low-latency reads for global applications
- Simple, relational data that fits the SQLite model
- Serverless architecture without managing database infrastructure
- Cost-effective storage for small to medium datasets
- Tight integration with Cloudflare Workers
D1 might not be the best fit for:
- Applications requiring real-time synchronization between multiple writers
- Very large datasets (hundreds of GB)
- Complex transactions spanning multiple databases
- Applications needing specialized database features (full-text search, geospatial queries)
D1 Architecture
Understanding how D1 works helps you design better applications:
flowchart TB
subgraph UserRequest["User Request"]
User["User (Global)"]
end
subgraph CloudflareNetwork["Cloudflare Global Network"]
Edge1["Edge Location 1"]
Edge2["Edge Location 2"]
Edge3["Edge Location 3"]
subgraph Worker["Cloudflare Worker"]
API["Your API Code"]
D1Binding["D1 Binding"]
end
subgraph D1Database["D1 Database"]
Primary["Primary<br/>(Writes)"]
Replica1["Read Replica"]
Replica2["Read Replica"]
end
end
User --> Edge1
User --> Edge2
User --> Edge3
Edge1 --> Worker
Edge2 --> Worker
Edge3 --> Worker
API --> D1Binding
D1Binding --> Primary
D1Binding --> Replica1
D1Binding --> Replica2
Primary -.->|"Replication"| Replica1
Primary -.->|"Replication"| Replica2
How D1 Handles Requests
- User requests arrive at the nearest Cloudflare edge location
- Workers execute your API code at the edge
- D1 bindings route queries to the optimal database location
- Read replicas serve read queries from nearby locations
- Primary database handles all write operations
This architecture means reads are fast (served from nearby replicas), while writes go to a central primary location to maintain consistency.
Local vs Remote D1
When developing with D1, you work with two different database environments:
Local D1 (Development)
During development, Wrangler creates a local SQLite database on your machine:
# Start local development server with local D1pnpm devLocal D1 characteristics:
| Aspect | Behavior |
|---|---|
| Location | .wrangler/state/v3/d1/ directory |
| Performance | Instant queries (no network) |
| Data persistence | Survives restarts, reset with reset:* scripts |
| Migrations | Applied with wrangler d1 migrations apply --local |
Remote D1 (Staging/Production)
In staging and production, your database runs on Cloudflare’s infrastructure:
# Apply migrations to remote databasewrangler d1 migrations apply YOUR_DATABASE_NAME --remoteRemote D1 characteristics:
| Aspect | Behavior |
|---|---|
| Location | Cloudflare’s global network |
| Performance | Depends on user proximity to replicas |
| Data persistence | Highly durable, replicated storage |
| Migrations | Applied with --remote flag |
Environment Parity
To avoid surprises in production, keep your environments aligned:
- Use the same schema across local and remote databases
- Test migrations locally before applying to remote
- Use similar data volumes when performance testing
- Run integration tests against local D1 before deploying
D1 Limitations
Understanding D1’s constraints helps you design appropriate solutions:
Size Limits
| Resource | Limit |
|---|---|
| Database size | 10 GB per database |
| Row size | 1 MB maximum |
| SQL query size | 100 KB maximum |
| Bound parameters | 100 per query |
Performance Considerations
| Aspect | Consideration |
|---|---|
| Write latency | Higher than reads (goes to primary) |
| Concurrent writes | Single-writer model (serialized) |
| Complex queries | May be slower than dedicated databases |
| Joins | Efficient for small-to-medium tables |
SQLite Compatibility
D1 supports most SQLite features with some exceptions:
Supported:
- Standard SQL queries (SELECT, INSERT, UPDATE, DELETE)
- Transactions and ACID compliance
- Indexes and constraints
- Common table expressions (CTEs)
- JSON functions
- Window functions
Not supported or limited:
ATTACH DATABASE(single database per binding)- User-defined functions (UDFs)
- Full-text search (FTS5) — currently in beta
- R-Tree spatial indexes
- Some
PRAGMAstatements
D1 Strengths
D1 offers compelling advantages for the right use cases:
Developer Experience
- Familiar SQL: If you know SQL, you know D1
- Local development: Full-featured local database with Wrangler
- Type safety: Excellent ORM support (Drizzle, Prisma)
- Zero configuration: Bindings just work with Workers
Operational Benefits
- No infrastructure: Cloudflare manages everything
- Automatic backups: Point-in-time recovery available
- Global distribution: Read replicas worldwide
- Cost-effective: Pay only for what you use
Performance Characteristics
| Operation | Performance |
|---|---|
| Simple reads | Sub-10ms from edge |
| Complex queries | Depends on data size and query complexity |
| Writes | Consistent latency to primary |
| Transactions | ACID-compliant with serializable isolation |
Integration Benefits
- Native Workers binding: No connection strings or pools
- Environment-aware: Automatic local/remote switching
- Migration-friendly: Works well with Drizzle Kit
- Wrangler CLI: Comprehensive tooling included
When D1 Shines
D1 is particularly well-suited for these scenarios:
- Content-driven sites: Blogs, documentation, marketing sites
- User-generated content: Comments, reviews, posts
- Configuration storage: Feature flags, settings, preferences
- Session management: User sessions, authentication data
- API backends: REST/GraphQL APIs with moderate traffic
- Multi-tenant apps: Isolated databases per tenant
Summary
D1 is a powerful choice for serverless applications that need:
- Global, low-latency data access
- Familiar SQL-based development
- Zero infrastructure management
- Tight Cloudflare Workers integration
Understanding these fundamentals prepares you for the next step: learning how Drizzle ORM makes working with D1 even better.