Run Express.js on Cloudflare Workers

As of August 5th, 2025 and wrangler 4.28.0, Cloudflare Workers extends its Node.js compatibility efforts, and now supports running Express.js apps directly and natively (in local development, production availability coming soon)!

Express.js has long provided the Node.js ecosystem with an incredibly ergonomic way to build web applications and APIs. While these didn't previously work directly with Cloudflare Workers, Hono, itty-router and others provided a familiar experience to end-users, but at the cost of some slight ergonomic differences. Now, you can use Express.js, as well as many other Node.js frameworks directly on Workers!

http support

The biggest unlock for Cloudflare Workers running express apps directly now, is the support of http.createServer via the enable_nodejs_http_server_modules compatibility flag, and then the new httpServerHandler API made available via cloudflare:node imports.

Example

Below is an example express app that when paired with modern Workers ergonomics like importable env, make for some really nice DX for those already familiar with these libraries.

Express.js Worker

import { httpServerHandler } from 'cloudflare:node';
import { env } from 'cloudflare:workers';
import express from 'express';

const app = express();

app.get('/hello', (req, res) => res.send('Hello, World!'));

type SaveDataRequest = express.Request<
	{},
	{},
	{ value?: string; }
>;
app.post('/save-data', express.json(), async (req: SaveDataRequest, res) => {
	const { value } = req.body;
	if (!value) {
		return res.status(400).json({ error: 'Value is required' });
	}
	await env.KV.put('something', value);
	return res.send();
});

app.get('/get-data', async (req, res) => {
	const data = await env.KV.get('something');
	return res.json({ data });
});

app.use((req, res) => res.status(404).send('Not Found'));

app.listen(8080);

export default httpServerHandler({ port: 8080 });

wrangler.toml

name = "test"
account_id = "xxx"
workers_dev = true

compatibility_date = "2025-07-30"
compatibility_flags = [
	"nodejs_compat",
	"enable_nodejs_http_modules",
	"enable_nodejs_http_server_modules",
	"experimental"
]
main = "src/worker.ts"

kv_namespaces = [
	{ binding = "KV", id = "abc" }
]

And then with curl http://127.0.0.1/hello-world after running via wrangler dev, you'll see Hello, World! - a full express.js app with all of the ergonomics of wrangler and the Cloudflare ecosystem!

So should I migrate away from Hono?

Probably not. Support for more Node.js frameworks lowers the barrier to entry for new Workers users coming from Node.js, but frameworks like Hono are still the gold standard in my opinion for modern Cloudflare Workers development.

It's incredibly cool and exciting however that older Node.js projects are now able to migrate to Workers much more quickly and seamlessly! Cloudflare's workerd runtime team continue to improve their Node.js compatibility all the time, and I look forward to a time where we can hopefully build truly runtime agnostic applications.

You've successfully subscribed to James Ross
Great! Next, complete checkout for full access to James Ross
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.