Migrate from Express / Node.js API
Re-expressing routes as Worker handlers is the simple part. The real work is the runtime gap — Workers is not Node. There's no long-lived process, no filesystem, no in-memory state across requests, no free-running timers, and native TCP database drivers don't run. This page maps each gap and points you at the skill that ports the handlers honestly.
pnpm create microservices-app@latest my-app --template saas-starter-sveltekit Local-first · no login · Node ≥ 20 · driven by the express-api-to-workers agent skill
Concept mapping
| Express / Node.js API | microservices.sh / Cloudflare | Note |
|---|---|---|
| Long-lived process + in-memory cache | Stateless per request; state in KV/D1/DO | No module-scope mutable state across requests |
| fs / local disk | R2 (objects), KV (small values) | No filesystem |
| process.env at runtime | Worker bindings + secrets | |
| Express middleware chain | Handler composition / module hooks | |
| req / res (Node) | Request / Response (Web Fetch) | |
| setInterval / background timers | Cron Triggers / Queues / waitUntil | No free-running timers |
| ws WebSocket server | Durable Objects + WebSocket | |
| Native DB drivers (pg, mysql2) | D1 / Drizzle or HTTP-based driver | TCP drivers don't run on Workers |
The migration
List routes by resource, inventory middleware (auth, validation, rate limiting, logging, CORS), and find runtime-gap usages (fs, native drivers, timers, in-memory caches, WebSocket servers).
Scaffold with create microservices-app and map resources to existing modules — people→customer, payments→payment, mail→email.
Re-express each route as a thin Worker handler delegating to a module use-case; convert middleware to composable steps or hooks; swap req/res for Web Request/Response.
Move the datastore with the Prisma/Supabase/Firebase skills, replace native DB drivers with D1/Drizzle, and shift background work to Cron Triggers or Queues.
Confirm migrated routes return equivalent responses, auth and validation behave as before, and no handler depends on a removed Node primitive.
What doesn't port 1:1
pnpm create microservices-app@latest my-app --template saas-starter-sveltekit Lands on these modules