Skip to content

First Deployment in 10 Minutes

In this chapter, you’ll deploy a working API to Cloudflare Workers and test it with Swagger UI. By the end, you’ll have a live API endpoint accessible from anywhere in the world.

Step 1: Clone the starter project

Open your terminal and clone the starter repository:

Terminal window
git clone https://github.com/d1-migration-mastery/starter.git
cd starter

Expected output:

Cloning into 'starter'...
remote: Enumerating objects: 42, done.
remote: Counting objects: 100% (42/42), done.
remote: Compressing objects: 100% (28/28), done.
Receiving objects: 100% (42/42), 12.34 KiB | 1.23 MiB/s, done.
Resolving deltas: 100% (15/15), done.

Step 2: Install dependencies

Install all required packages using pnpm:

Terminal window
pnpm install

Expected output:

Packages: +156
++++++++++++++++++++++++++++++++++++++++++++++++++++
Progress: resolved 156, reused 142, downloaded 14, added 156, done
dependencies:
+ @elysiajs/swagger 1.3.1
+ drizzle-orm 0.38.0
+ elysia 1.2.0
devDependencies:
+ @cloudflare/workers-types 4.20250109.0
+ drizzle-kit 0.30.0
+ typescript 5.7.3
+ wrangler 3.105.0
...

Step 3: Login to Cloudflare

Authenticate with your Cloudflare account:

Terminal window
wrangler login

Expected output:

⛅️ wrangler 3.105.0
-------------------
Attempting to login via OAuth...
Opening a link in your default browser: https://dash.cloudflare.com/oauth2/auth?...
Successfully logged in.

A browser window will open asking you to authorize Wrangler. Click Allow to continue.

Step 4: Create your D1 database

Create a new D1 database for your project:

Terminal window
wrangler d1 create d1-mastery-db

Expected output:

⛅️ wrangler 3.105.0
-------------------
✅ Successfully created DB 'd1-mastery-db' in region WNAM
Created your new D1 database.
[[d1_databases]]
binding = "DB"
database_name = "d1-mastery-db"
database_id = "a1b2c3d4-e5f6-7890-abcd-ef1234567890"

Step 5: Configure wrangler.toml

Open wrangler.toml and update the staging environment with your database ID:

wrangler.toml
# Staging environment
[env.staging]
name = "d1-migration-mastery-staging"
[[env.staging.d1_databases]]
binding = "DB"
database_name = "d1-mastery-staging"
database_id = "a1b2c3d4-e5f6-7890-abcd-ef1234567890" # Replace with your ID

The starter project includes three environments:

  • local: For local development (uses a local SQLite file)
  • staging: For testing deployments (you’re setting this up now)
  • production: For your live application (covered in later chapters)

Step 6: Run migrations

Before deploying, apply the database migrations to create your tables:

Terminal window
pnpm db:migrate:staging

Expected output:

⛅️ wrangler 3.105.0
-------------------
🌀 Executing on remote database d1-mastery-staging (a1b2c3d4-e5f6-7890-abcd-ef1234567890):
🌀 To execute on your local development database, remove the --remote flag.
Migrations to be applied:
┌─────────────────────────────┐
│ name │
├─────────────────────────────┤
│ 0000_initial_migration.sql │
│ 0001_create_users_table.sql │
│ 0002_create_posts_table.sql │
└─────────────────────────────┘
✔ About to apply 3 migration(s)
Your database is now up to date.

Step 7: Deploy to Cloudflare Workers

Deploy your API to the staging environment:

Terminal window
pnpm deploy:staging

Expected output:

⛅️ wrangler 3.105.0
-------------------
Your worker has access to the following bindings:
- D1 Databases:
- DB: d1-mastery-staging (a1b2c3d4-e5f6-7890-abcd-ef1234567890)
Total Upload: 125.67 KiB / gzip: 32.45 KiB
Uploaded d1-migration-mastery-staging (2.34 sec)
Published d1-migration-mastery-staging (0.56 sec)
https://d1-migration-mastery-staging.your-subdomain.workers.dev
Current Deployment ID: abc12345-def6-7890-ghij-klmnopqrstuv

🎉 Your API is now live! Copy the URL from the output.

Step 8: Test with Swagger UI

Append /swagger to your deployment URL and open it in your browser:

https://d1-migration-mastery-staging.your-subdomain.workers.dev/swagger

What you’ll see

The Swagger UI provides interactive API documentation with:

  • API Overview: Title, description, and version of your API
  • Endpoints List: All available routes organized by tags
    • GET /users - List all users
    • POST /users - Create a new user
    • GET /users/{id} - Get a user by ID
    • PUT /users/{id} - Update a user
    • DELETE /users/{id} - Delete a user
    • Similar endpoints for /posts
  • Try It Out: Click any endpoint to expand it, then click “Try it out” to make real API requests
  • Request/Response Schemas: See the exact shape of request bodies and responses

Try creating a user

  1. Click on POST /users to expand it
  2. Click Try it out
  3. Enter a request body:
    {
    "name": "John Doe",
    "email": "john@example.com"
    }
  4. Click Execute
  5. See the response with your new user’s ID

Verify local development

Before moving on, verify that local development also works:

Terminal window
pnpm dev

Expected output:

⛅️ wrangler 3.105.0
-------------------
⎔ Starting local server...
[wrangler:inf] Ready on http://localhost:8787

Visit http://localhost:8787/swagger to access the same Swagger UI locally.

Troubleshooting

Error: “You need to provide a valid database_id”

Cause: The database_id in wrangler.toml is still a placeholder.

Solution: Run wrangler d1 create d1-mastery-db and copy the actual database_id into your wrangler.toml file.

Error: “Authentication error”

Cause: Your Wrangler session has expired or you haven’t logged in.

Solution: Run wrangler login again and authorize the connection.

Error: “Database not found”

Cause: You’re trying to deploy to an environment with a database that doesn’t exist.

Solution: Make sure you:

  1. Created the database with wrangler d1 create
  2. Copied the correct database_id to the right environment in wrangler.toml
  3. Are deploying to the same environment (e.g., --env staging)

Error: “No migrations to apply” but tables are missing

Cause: Migrations may have run before but the database was deleted or recreated.

Solution: Delete and recreate your D1 database, then run migrations again:

Terminal window
wrangler d1 delete d1-mastery-db
wrangler d1 create d1-mastery-db
# Update wrangler.toml with the new database_id
pnpm db:migrate:staging

Swagger UI shows no endpoints

Cause: The API failed to start or has an error.

Solution:

  1. Check the browser’s developer console for errors
  2. Check Cloudflare dashboard logs: Workers & Pages → your worker → Logs
  3. Verify your code has no TypeScript errors: pnpm typecheck

”Error: Failed to execute ‘fetch’ on ‘ServiceWorkerGlobalScope’”

Cause: CORS issue when testing from a different origin.

Solution: This typically happens during development. Make sure you’re accessing the Swagger UI directly from the worker URL, not from a different domain.

What’s next?

Congratulations! You’ve successfully:

  • ✅ Cloned and set up the starter project
  • ✅ Created a D1 database on Cloudflare
  • ✅ Deployed your first API to Cloudflare Workers
  • ✅ Tested your API using Swagger UI

In the next chapter, you’ll learn about D1 fundamentals and how SQLite works at the edge.