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:
git clone https://github.com/d1-migration-mastery/starter.gitcd starterExpected 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:
pnpm installExpected 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:
wrangler loginExpected 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:
wrangler d1 create d1-mastery-dbExpected output:
⛅️ wrangler 3.105.0-------------------
✅ Successfully created DB 'd1-mastery-db' in region WNAMCreated 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:
# 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 IDThe 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:
pnpm db:migrate:stagingExpected 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:
pnpm deploy:stagingExpected 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 KiBUploaded d1-migration-mastery-staging (2.34 sec)Published d1-migration-mastery-staging (0.56 sec) https://d1-migration-mastery-staging.your-subdomain.workers.devCurrent 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/swaggerWhat 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 usersPOST /users- Create a new userGET /users/{id}- Get a user by IDPUT /users/{id}- Update a userDELETE /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
- Click on
POST /usersto expand it - Click Try it out
- Enter a request body:
{"name": "John Doe","email": "john@example.com"}
- Click Execute
- See the response with your new user’s ID
Verify local development
Before moving on, verify that local development also works:
pnpm devExpected output:
⛅️ wrangler 3.105.0-------------------
⎔ Starting local server...[wrangler:inf] Ready on http://localhost:8787Visit 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:
- Created the database with
wrangler d1 create - Copied the correct
database_idto the right environment inwrangler.toml - 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:
wrangler d1 delete d1-mastery-dbwrangler d1 create d1-mastery-db# Update wrangler.toml with the new database_idpnpm db:migrate:stagingSwagger UI shows no endpoints
Cause: The API failed to start or has an error.
Solution:
- Check the browser’s developer console for errors
- Check Cloudflare dashboard logs: Workers & Pages → your worker → Logs
- 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.