Getting started
This guide instructs you through:
- Creating your first database using D1, Cloudflare's native serverless SQL database.
- Creating a schema and querying your database via the command-line.
- Connecting a Cloudflare Worker to your D1 database using bindings, and querying your D1 database programmatically.
You can perform these tasks through the CLI or through the Cloudflare dashboard.
If you want to skip the steps and get started quickly, click on the button below.
This creates a repository in your GitHub account and deploys the application to Cloudflare Workers. Use this option if you are familiar with Cloudflare Workers, and wish to skip the step-by-step guidance.
You may wish to manually follow the steps if you are new to Cloudflare Workers.
- Sign up for a Cloudflare account ↗.
- Install
Node.js
↗.
Node.js version manager
Use a Node version manager like Volta ↗ or nvm ↗ to avoid permission issues and change Node.js versions. Wrangler, discussed later in this guide, requires a Node version of 16.17.0
or later.
Create a new Worker as the means to query your database.
-
Create a new project named
d1-tutorial
by running:Terminal window npm create cloudflare@latest -- d1-tutorialTerminal window yarn create cloudflare d1-tutorialTerminal window pnpm create cloudflare@latest d1-tutorialFor setup, select the following options:
- For What would you like to start with?, choose
Hello World Starter
. - For Which template would you like to use?, choose
Worker only
. - For Which language do you want to use?, choose
TypeScript
. - For Do you want to use git for version control?, choose
Yes
. - For Do you want to deploy your application?, choose
No
(we will be making some changes before deploying).
This creates a new
d1-tutorial
directory as illustrated below.Directoryd1-tutorial
Directorynode_modules/
- …
Directorytest/
- …
Directorysrc
- index.ts
- package-lock.json
- package.json
- testconfig.json
- vitest.config.mts
- worker-configuration.d.ts
- wrangler.jsonc
Your new
d1-tutorial
directory includes:- A
"Hello World"
Worker inindex.ts
. - A Wrangler configuration file. This file is how your
d1-tutorial
Worker accesses your D1 database.
- For What would you like to start with?, choose
- Log in to your Cloudflare dashboard ↗ and select your account.
- Go to your account > Compute (Workers) > Workers & Pages.
- Select Create.
- Under Start from a template, select Hello world.
- Name your Worker. For this tutorial, name your Worker
d1-tutorial
. - Select Deploy.
A D1 database is conceptually similar to many other SQL databases: a database may contain one or more tables, the ability to query those tables, and optional indexes. D1 uses the familiar SQL query language ↗ (as used by SQLite).
To create your first D1 database:
-
Change into the directory you just created for your Workers project:
Terminal window cd d1-tutorial -
Run the following
wrangler@latest d1
command and give your database a name. In this tutorial, the database is namedprod-d1-tutorial
:Terminal window npx wrangler@latest d1 create prod-d1-tutorial✅ Successfully created DB 'prod-d1-tutorial' in region WEURCreated your new D1 database.{"d1_databases": [{"binding": "DB","database_name": "prod-d1-tutorial","database_id": "<unique-ID-for-your-database>"}]}
This creates a new D1 database and outputs the binding configuration needed in the next step.
- Go to Storage & Databases > D1 SQL Database.
- Select Create Database.
- Name your database. For this tutorial, name your D1 database
prod-d1-tutorial
. - (Optional) Provide a location hint. Location hint is an optional parameter you can provide to indicate your desired geographical location for your database. Refer to Provide a location hint for more information.
- Select Create.
You must create a binding for your Worker to connect to your D1 database. Bindings allow your Workers to access resources, like D1, on the Cloudflare developer platform.
To bind your D1 database to your Worker:
You create bindings by updating your Wrangler file.
-
Copy the lines obtained from step 2 from your terminal.
-
Add them to the end of your Wrangler file.
{"d1_databases": [{"binding": "DB","database_name": "prod-d1-tutorial","database_id": "<unique-ID-for-your-database>"}]}[[d1_databases]]binding = "DB" # available in your Worker on env.DBdatabase_name = "prod-d1-tutorial"database_id = "<unique-ID-for-your-database>"Specifically:
- The value (string) you set for
binding
is the binding name, and is used to reference this database in your Worker. In this tutorial, name your bindingDB
. - The binding name must be a valid JavaScript variable name ↗. For example,
binding = "MY_DB"
orbinding = "productionDB"
would both be valid names for the binding. - Your binding is available in your Worker at
env.<BINDING_NAME>
and the D1 Workers Binding API is exposed on this binding.
- The value (string) you set for
You can also bind your D1 database to a Pages Function. For more information, refer to Functions Bindings for D1.
You create bindings by adding them to the Worker you have created.
-
Go to Compute (Workers) > Workers & Pages.
-
Select the
d1-tutorial
Worker you created in step 1. -
Select Settings.
-
Scroll to Bindings, then select Add.
-
Select D1 database.
-
Name your binding in Variable name, then select the
prod-d1-tutorial
D1 database you created in step 2 from the dropdown menu. For this tutorial, name your bindingDB
. -
Select Deploy to deploy your binding. When deploying, there are two options:
- Deploy: Immediately deploy the binding to 100% of your audience.
- Save version: Save a version of the binding which you can deploy in the future.
For this tutorial, select Deploy.
After correctly preparing your Wrangler configuration file, set up your database. Create a schema.sql
file using the SQL syntax below to initialize your database.
-
Copy the following code and save it as a
schema.sql
file in thed1-tutorial
Worker directory you created in step 1:DROP TABLE IF EXISTS Customers;CREATE TABLE IF NOT EXISTS Customers (CustomerId INTEGER PRIMARY KEY, CompanyName TEXT, ContactName TEXT);INSERT INTO Customers (CustomerID, CompanyName, ContactName) VALUES (1, 'Alfreds Futterkiste', 'Maria Anders'), (4, 'Around the Horn', 'Thomas Hardy'), (11, 'Bs Beverages', 'Victoria Ashworth'), (13, 'Bs Beverages', 'Random Name'); -
Initialize your database to run and test locally first. Bootstrap your new D1 database by running:
Terminal window npx wrangler d1 execute prod-d1-tutorial --local --file=./schema.sql⛅️ wrangler 4.13.2-------------------🌀 Executing on local database prod-d1-tutorial (<DATABASE_ID>) from .wrangler/state/v3/d1:🌀 To execute on your remote database, add a --remote flag to your wrangler command.🚣 3 commands executed successfully. -
Validate that your data is in the database by running:
Terminal window npx wrangler d1 execute prod-d1-tutorial --local --command="SELECT * FROM Customers"🌀 Mapping SQL input into an array of statements🌀 Executing on local database production-db-backend (<DATABASE_ID>) from .wrangler/state/v3/d1:┌────────────┬─────────────────────┬───────────────────┐│ CustomerId │ CompanyName │ ContactName │├────────────┼─────────────────────┼───────────────────┤│ 1 │ Alfreds Futterkiste │ Maria Anders │├────────────┼─────────────────────┼───────────────────┤│ 4 │ Around the Horn │ Thomas Hardy │├────────────┼─────────────────────┼───────────────────┤│ 11 │ Bs Beverages │ Victoria Ashworth │├────────────┼─────────────────────┼───────────────────┤│ 13 │ Bs Beverages │ Random Name │└────────────┴─────────────────────┴───────────────────┘
Use the Dashboard to create a table and populate it with data.
-
Go to Storage & Databases > D1 SQL Database.
-
Select the
prod-d1-tutorial
database you created in step 2. -
Select Console.
-
Paste the following SQL snippet.
DROP TABLE IF EXISTS Customers;CREATE TABLE IF NOT EXISTS Customers (CustomerId INTEGER PRIMARY KEY, CompanyName TEXT, ContactName TEXT);INSERT INTO Customers (CustomerID, CompanyName, ContactName) VALUES (1, 'Alfreds Futterkiste', 'Maria Anders'), (4, 'Around the Horn', 'Thomas Hardy'), (11, 'Bs Beverages', 'Victoria Ashworth'), (13, 'Bs Beverages', 'Random Name'); -
Select Execute. This creates a table called
Customers
in yourprod-d1-tutorial
database. -
Select Tables, then select the
Customers
table to view the contents of the table.
After you have set up your database, run an SQL query from within your Worker.
-
Navigate to your
d1-tutorial
Worker and open theindex.ts
file. Theindex.ts
file is where you configure your Worker's interactions with D1. -
Clear the content of
index.ts
. -
Paste the following code snippet into your
index.ts
file:index.js export default {async fetch(request, env) {const { pathname } = new URL(request.url);if (pathname === "/api/beverages") {// If you did not use `DB` as your binding name, change it hereconst { results } = await env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = ?",).bind("Bs Beverages").all();return Response.json(results);}return new Response("Call /api/beverages to see everyone who works at Bs Beverages",);},};index.ts export interface Env {// If you set another name in the Wrangler config file for the value for 'binding',// replace "DB" with the variable name you defined.DB: D1Database;}export default {async fetch(request, env): Promise<Response> {const { pathname } = new URL(request.url);if (pathname === "/api/beverages") {// If you did not use `DB` as your binding name, change it hereconst { results } = await env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = ?",).bind("Bs Beverages").all();return Response.json(results);}return new Response("Call /api/beverages to see everyone who works at Bs Beverages",);},} satisfies ExportedHandler<Env>;In the code above, you:
- Define a binding to your D1 database in your code. This binding matches the
binding
value you set in the Wrangler configuration file underd1_databases
. - Query your database using
env.DB.prepare
to issue a prepared query with a placeholder (the?
in the query). - Call
bind()
to safely and securely bind a value to that placeholder. In a real application, you would allow a user to pass theCompanyName
they want to list results for. Usingbind()
prevents users from executing arbitrary SQL (known as "SQL injection") against your application and deleting or otherwise modifying your database. - Execute the query by calling
all()
to return all rows (or none, if the query returns none). - Return your query results, if any, in JSON format with
Response.json(results)
.
- Define a binding to your D1 database in your code. This binding matches the
After configuring your Worker, you can test your project locally before you deploy globally.
You can query your D1 database using your Worker.
-
Go to Compute (Workers) > Workers & Pages.
-
Select the
d1-tutorial
Worker you created. -
Select the Edit code icon (</>).
-
Clear the contents of the
worker.js
file, then paste the following code:export default {async fetch(request, env) {const { pathname } = new URL(request.url);if (pathname === "/api/beverages") {// If you did not use `DB` as your binding name, change it hereconst { results } = await env.DB.prepare("SELECT * FROM Customers WHERE CompanyName = ?").bind("Bs Beverages").all();return new Response(JSON.stringify(results), {headers: { 'Content-Type': 'application/json' }});}return new Response("Call /api/beverages to see everyone who works at Bs Beverages");},}; -
Select Save.
Deploy your application on Cloudflare's global network.
To deploy your Worker to production using Wrangler, you must first repeat the database configuration steps after replacing the --local
flag with the --remote
flag to give your Worker data to read. This creates the database tables and imports the data into the production version of your database.
-
Create tables and add entries to your remote database with the
schema.sql
file you created in step 4. Entery
to confirm your decision.Terminal window npx wrangler d1 execute prod-d1-tutorial --remote --file=./schema.sql✔ ⚠️ This process may take some time, during which your D1 database will be unavailable to serve queries.Ok to proceed? y🚣 Executed 3 queries in 0.00 seconds (5 rows read, 6 rows written)Database is currently at bookmark 00000002-00000004-00004ef1-ad4a06967970ee3b20860c86188a4b31.┌────────────────────────┬───────────┬──────────────┬────────────────────┐│ Total queries executed │ Rows read │ Rows written │ Database size (MB) │├────────────────────────┼───────────┼──────────────┼────────────────────┤│ 3 │ 5 │ 6 │ 0.02 │└────────────────────────┴───────────┴──────────────┴────────────────────┘ -
Validate the data is in production by running:
Terminal window npx wrangler d1 execute prod-d1-tutorial --remote --command="SELECT * FROM Customers"⛅️ wrangler 4.13.2-------------------🌀 Executing on remote database prod-d1-tutorial (<DATABASE_ID>):🌀 To execute on your local development database, remove the --remote flag from your wrangler command.🚣 Executed 1 command in 0.4069ms┌────────────┬─────────────────────┬───────────────────┐│ CustomerId │ CompanyName │ ContactName │├────────────┼─────────────────────┼───────────────────┤│ 1 │ Alfreds Futterkiste │ Maria Anders │├────────────┼─────────────────────┼───────────────────┤│ 4 │ Around the Horn │ Thomas Hardy │├────────────┼─────────────────────┼───────────────────┤│ 11 │ Bs Beverages │ Victoria Ashworth │├────────────┼─────────────────────┼───────────────────┤│ 13 │ Bs Beverages │ Random Name │└────────────┴─────────────────────┴───────────────────┘ -
Deploy your Worker to make your project accessible on the Internet. Run:
Terminal window npx wrangler deploy⛅️ wrangler 4.13.2-------------------Total Upload: 0.19 KiB / gzip: 0.16 KiBYour worker has access to the following bindings:- D1 Databases:- DB: prod-d1-tutorial (<DATABASE_ID>)Uploaded d1-tutorial (3.76 sec)Deployed d1-tutorial triggers (2.77 sec)https://d1-tutorial.<YOUR_SUBDOMAIN>.workers.devCurrent Version ID: <VERSION_ID>You can now visit the URL for your newly created project to query your live database.
For example, if the URL of your new Worker is
d1-tutorial.<YOUR_SUBDOMAIN>.workers.dev
, accessinghttps://d1-tutorial.<YOUR_SUBDOMAIN>.workers.dev/api/beverages
sends a request to your Worker that queries your live database directly. -
Test your database is running successfully. Add
/api/beverages
to the provided Wrangler URL. For example,https://d1-tutorial.<YOUR_SUBDOMAIN>.workers.dev/api/beverages
.
- Go to Compute (Workers) > Workers & Pages.
- Select your
d1-tutorial
Worker. - Select Deployments.
- From the Version History table, select Deploy version.
- From the Deploy version page, select Deploy.
This deploys the latest version of the Worker code to production.
If you are using D1 with Wrangler, you can test your database locally. While in your project directory:
-
Run
wrangler dev
:Terminal window npx wrangler devWhen you run
wrangler dev
, Wrangler provides a URL (most likelylocalhost:8787
) to review your Worker. -
Go to the URL.
The page displays
Call /api/beverages to see everyone who works at Bs Beverages
. -
Test your database is running successfully. Add
/api/beverages
to the provided Wrangler URL. For example,localhost:8787/api/beverages
.
If successful, the browser displays your data.
To delete your database:
Run:
npx wrangler d1 delete prod-d1-tutorial
-
Go to Storages & Databases > D1 SQL Database.
-
Select your
prod-d1-tutorial
D1 database. -
Select Settings.
-
Select Delete.
-
Type the name of the database (
prod-d1-tutorial
) to confirm the deletion.
If you want to delete your Worker:
Run:
npx wrangler delete d1-tutorial
-
Go to Compute (Workers) > Workers & Pages.
-
Select your
d1-tutorial
Worker. -
Select Settings.
-
Scroll to the bottom of the page, then select Delete.
-
Type the name of the Worker (
d1-tutorial
) to confirm the deletion.
In this tutorial, you have:
- Created a D1 database
- Created a Worker to access that database
- Deployed your project globally
If you have any feature requests or notice any bugs, share your feedback directly with the Cloudflare team by joining the Cloudflare Developers community on Discord ↗.
- See supported Wrangler commands for D1.
- Learn how to use D1 Worker Binding APIs within your Worker, and test them from the API playground.
- Explore community projects built on D1.
Was this helpful?
- Resources
- API
- New to Cloudflare?
- Products
- Sponsorships
- Open Source
- Support
- Help Center
- System Status
- Compliance
- GDPR
- Company
- cloudflare.com
- Our team
- Careers
- 2025 Cloudflare, Inc.
- Privacy Policy
- Terms of Use
- Report Security Issues
- Trademark