Deploy an Express.js application on Clou·续
This endpoint validates the input, checks the email format, and inserts a new member into the database. It also handles duplicate email addresses by checking for unique constraint violations.
8. Implement update operation
Add an endpoint to update existing members. Add the following route to your src/index.ts file:
src/index.tsts
app.put("/api/members/:id", async (req, res) => {
try {
const { id } = req.params;
const { name, email } = req.body;
// Validate input
if (!name && !email) {
return res.status(400).json({
success: false,
error: "At least one field (name or email) is required",
});
}
// Basic email validation if provided (simplified for tutorial purposes)
// For production, consider using a validation library or more comprehensive checks
if (email && (!email.includes("@") || !email.includes("."))) {
return res.status(400).json({
success: false,
error: "Invalid email format",
});
}
// Build dynamic update query
const updates: string[] = [];
const values: any[] = [];
if (name) {
updates.push("name = ?");
values.push(name);
}
if (email) {
updates.push("email = ?");
values.push(email);
}
values.push(id);
const result = await env.DB.prepare(
`UPDATE members SET ${updates.join(", ")} WHERE id = ?`
)
.bind(...values)
.run();
if (result.meta.changes === 0) {
return res
.status(404)
.json({ success: false, error: "Member not found" });
}
res.json({ success: true, message: "Member updated successfully" });
} catch (error: any) {
if (error.message?.includes("UNIQUE constraint failed")) {
return res.status(409).json({
success: false,
error: "Email already exists",
});
}
res.status(500).json({ success: false, error: "Failed to update member" });
}
});
This endpoint allows updating either the name, email, or both fields of an existing member. It builds a dynamic SQL query based on the provided fields.
9. Implement delete operation
Add an endpoint to delete members. Add the following route to your src/index.ts file:
src/index.tsts
// DELETE - Delete a member
app.delete("/api/members/:id", async (req, res) => {
try {
const { id } = req.params;
const result = await env.DB.prepare("DELETE FROM members WHERE id = ?")
.bind(id)
.run();
if (result.meta.changes === 0) {
return res
.status(404)
.json({ success: false, error: "Member not found" });
}
res.json({ success: true, message: "Member deleted successfully" });
} catch (error) {
res.status(500).json({ success: false, error: "Failed to delete member" });
}
});
This endpoint deletes a member by their ID and returns an error if the member does not exist.
10. Test locally
Start the development server to test your API locally:
npm run dev
The development server will start, and you can access your API at http://localhost:8787.
Open a new terminal window and test the endpoints using curl:
Get all memberssh
curl http://localhost:8787/api/members
{
"success": true,
"members": [
{
"id": 1,
"name": "Alice Johnson",
"email": "alice@example.com",
"joined_date": "2024-01-15"
},
{
"id": 2,
"name": "Bob Smith",
"email": "bob@example.com",
"joined_date": "2024-02-20"
},
{
"id": 3,
"name": "Carol Williams",
"email": "carol@example.com",
"joined_date": "2024-03-10"
}
]
}
Test creating a new member:
Create a membersh
curl -X POST http://localhost:8787/api/members \
-H "Content-Type: application/json" \
-d '{"name": "David Brown", "email": "david@example.com"}'
{
"success": true,
"message": "Member created successfully",
"id": 4
}
Test getting a single member:
Get a member by IDsh
curl http://localhost:8787/api/members/1
Test updating a member:
Update a membersh
curl -X PUT http://localhost:8787/api/members/1 \
-H "Content-Type: application/json" \
-d '{"name": "Alice Cooper"}'
Test deleting a member:
Delete a membersh
curl -X DELETE http://localhost:8787/api/members/4
11. Deploy to Cloudflare Workers
Before deploying to production, execute the schema file against your remote (production) database:
npx wrangler d1 execute members-db --remote --file=./schemas/schema.sql
Now deploy your application to the Cloudflare network:
npm run deploy
⛅️ wrangler 4.44.0
───────────────────
Total Upload: 1743.64 KiB / gzip: 498.65 KiB
Worker Startup Time: 48 ms
Your Worker has access to the following bindings:
Binding Resource
env.DB (members-db) D1 Database
Uploaded express-d1-app (2.99 sec)
Deployed express-d1-app triggers (5.26 sec)
https://<your-subdomain>.workers.dev
Current Version ID: <version-id>
After successful deployment, Wrangler will output your Worker's URL.
12. Test production deployment
Test your deployed API using the provided URL. Replace <your-worker-url> with your actual Worker URL:
Test production APIsh
curl https://<your-worker-url>/api/members
You should see the same member data you created in the production database.
Create a new member in production:
Create a member in productionsh
curl -X POST https://<your-worker-url>/api/members \
-H "Content-Type: application/json" \
-d '{"name": "Eva Martinez", "email": "eva@example.com"}'
Your Express.js application with D1 database is now running on Cloudflare Workers.
Conclusion
In this tutorial, you built a Members Registry API using Express.js and D1 database, then deployed it to Cloudflare Workers. You implemented full CRUD operations (Create, Read, Update, Delete) and learned how to:
- Set up an Express.js application for Cloudflare Workers
- Create and configure a D1 database with bindings
- Implement database operations using D1's prepared statements
- Test your API locally and in production
Next steps
- Learn more about D1 database features
- Explore Workers routing and middleware
- Add authentication to your API using Workers authentication
- Implement pagination for large datasets using D1 query optimization
Was this helpful?
YesNo
On this page
{"@context":"https://schema.org","@type":"TechArticle","@id":"https://developers.cloudflare.com/workers/tutorials/deploy-an-express-app/#page","headline":"Deploy an Express.js application on Cloudflare Workers","description":"Learn how to deploy an Express.js application on Cloudflare Workers.","url":"https://developers.cloudflare.com/workers/tutorials/deploy-an-express-app/","inLanguage":"en","image":"https://developers.cloudflare.com/workers/tutorials/deploy-an-express-app/og.png?v=9aacd24e06f4a468","dateModified":"2026-08-25","publisher":{"@type":"Organization","name":"Cloudflare","description":"One platform for your apps, agents, and workforce. Build, secure, and scale without managing infrastructure","url":"https://www.cloudflare.com/","sameAs":["https://github.com/cloudflare","https://www.linkedin.com/company/cloudflare","https://x.com/cloudflare"],"logo":{"@type":"ImageObject","url":"https://developers.cloudflare.com/logo.svg"},"address":{"@type":"PostalAddress","streetAddress":"101 Townsend St","addressLocality":"San Francisco","addressRegion":"CA","postalCode":"94107","addressCountry":"US"},"contactPoint":[{"@type":"ContactPoint","contactType":"Customer Support","url":"https://support.cloudflare.com/","availableLanguage":["English"]},{"@type":"ContactPoint","contactType":"Sales","url":"https://www.cloudflare.com/contact/","availableLanguage":["English"]}]},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"},"keywords":["TypeScript"]}
description: This tutorial explains how to programmatically generate a custom YouTube thumbnail using Cloudflare Workers. You may want to customize the thumbnail's design, call-to-actions and images used to encourage more viewers to watch your video. title: Generate YouTube thumbnails with Workers and Cloudflare Image Resizing image: https://developers.cloudflare.com/workers/tutorials/generate-youtube-thumbnails-with-workers-and-images/og.png?v=de5ab2985a819cd9
Documentation Index
Fetch the complete documentation index at: https://developers.cloudflare.com/workers/llms.txt
Use this file to discover all available pages before exploring further.
Docs