Back to Blog
Lesson 20 of the Cloudflare: Cloudflare for Developers: DNS to CDN course
July 28, 20264 min read

Introduction to D1 SQL Database: Serverless SQLite for Workers

Learn how to use D1, Cloudflare's serverless SQLite database. This guide covers creating your first instance, basic SQL, and configuring bindings in Wrangler.

Close-up of colorful programming code displayed on a monitor screen.

Previously in this course, we covered integrating R2 with workers, which allowed us to store and retrieve binary assets like images. Now, we’re moving from unstructured storage to structured data. In this lesson, you will learn how to provision a D1 instance, understand the basics of SQL, and bridge your Worker to your database using Wrangler bindings.

What is D1?

D1 is Cloudflare’s serverless relational database, powered by SQLite. Unlike traditional databases where you manage connection pools, hardware provisioning, or complex scaling rules, D1 is designed to be queried directly from your Worker. Because it’s based on SQLite, it provides a familiar, powerful SQL interface while operating in a distributed, edge-native environment.

If you are new to relational databases, I recommend brushing up on the logical vs physical schema to understand how we map application data to storage.

Creating Your First D1 Database

Everything begins with the Wrangler CLI. Before you can write a single line of SQL, you must provision an instance on Cloudflare's global network.

Run the following command in your terminal:

Bash
npx wrangler d1 create my-first-database

Once this finishes, Wrangler will output a binding configuration. It looks something like this:

TOML
[[d1_databases]]
binding = "DB"
database_name = "my-first-database"
database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

Copy this snippet into your wrangler.toml file. This is the "binding"—it tells your Worker that whenever it sees the variable env.DB, it should direct requests to your specific D1 instance.

SQL Basics: The Language of Data

SQL (Structured Query Language) is how we interact with D1. Even if you've never used a database, you’ve likely encountered the concept of a "table." Think of a table as a spreadsheet with columns (attributes) and rows (records).

Here are the three fundamental commands you will use daily:

CommandPurpose
CREATE TABLEDefines the structure of your data.
INSERT INTOAdds a new row of data to a table.
SELECTRetrieves data based on specific conditions.

When designing your tables, remember the importance of primary keys and identifiers to ensure every piece of data is unique and retrievable.

Configuring Bindings in Your Worker

To use the database in your code, you access it via the env object passed to your handler. Because we named the binding DB in our wrangler.toml, it becomes available as env.DB.

Here is a simple example of how to execute a basic SQL query inside a Worker:

JAVASCRIPT
export default {
  async fetch(request, env, ctx) {
    // We execute a raw SQL query using the DB binding
    const { results } = await env.DB.prepare(
      "SELECT * FROM users WHERE status = ?"
    )
    .bind(CE9178">'active')
    .all();

    return Response.json(results);
  },
};

Hands-on Exercise

  1. Provision: Run npx wrangler d1 create project-db and add the output to your wrangler.toml.
  2. Explore: Open the Cloudflare Dashboard, navigate to Workers & Pages > D1, and click your new database. Use the "Console" tab to run a simple command: CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT);.
  3. Verify: Insert a row using INSERT INTO test (name) VALUES ('Developer'); and then select it with SELECT * FROM test;.

Common Pitfalls

  • Hardcoding IDs: Never hardcode your database_id in your actual code; always use the wrangler.toml binding.
  • Synchronous Thinking: Remember that database operations are asynchronous. Always use await when calling .prepare() or .all().
  • Missing Migrations: While you can run SQL in the dashboard for testing, production databases should always be managed via implementing schema migrations to ensure consistency across environments.

Frequently Asked Questions

Q: Is D1 just a standard SQLite file? A: It uses the SQLite dialect, but it runs on Cloudflare's architecture, meaning it handles replication and global access for you.

Q: Can I connect to D1 from my local machine? A: Yes, Wrangler allows you to run local migrations and queries against a local SQLite file that mimics D1 behavior.

Q: How many D1 databases can I have? A: The number depends on your Cloudflare plan, but for most developers, the generous free tier is more than enough to get started.

Recap

We’ve successfully provisioned a D1 database, linked it to our project via wrangler.toml, and executed our first query. By leveraging SQLite, we gain the power of relational data without the overhead of traditional database management.

Up next: Schema Design for D1, where we will write our first migration file to define the structure for our project.

Similar Posts