<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/migrating-express-and-koa-apps-to-cloudflare-workers-node-js-compatibility-production-guide-wiuwlhzj1" -->

---
title: Migrating Express and Koa Apps to Cloudflare Workers:...
description: A production migration guide for moving Express and Koa applications to Cloudflare Workers using the nodejs_compat_v2 flag introduced in 2025. Covers the...
canonical: https://daily.dev/posts/migrating-express-and-koa-apps-to-cloudflare-workers-node-js-compatibility-production-guide-wiuwlhzj1
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Migrating Express and Koa Apps to Cloudflare Workers: Node.js Compatibility Production Guide | daily.dev
og:description: A production migration guide for moving Express and Koa applications to Cloudflare Workers using the nodejs_compat_v2 flag introduced in 2025. Covers the...
og:url: https://daily.dev/posts/migrating-express-and-koa-apps-to-cloudflare-workers-node-js-compatibility-production-guide-wiuwlhzj1
og:image: https://api.daily.dev/og/posts/wiUwlHzj1.png
og:image:alt: Migrating Express and Koa Apps to Cloudflare Workers: Node.js Compatibility Production Guide
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrating Express and Koa Apps to Cloudflare Workers: Node.js Compatibility Production Guide

**[SitePoint](https://daily.dev/sources/sitepoint)** · 20 min read · 0 upvotes · 0 comments

## Summary

A production migration guide for moving Express and Koa applications to Cloudflare Workers using the nodejs_compat_v2 flag introduced in 2025. Covers the httpServerHandler pattern that bridges Node.js HTTP frameworks with the Workers fetch handler, wrangler.toml configuration including compatibility_date requirements, a detailed middleware compatibility matrix (what works, what fails, and what needs replacement), strategies for replacing filesystem-dependent middleware and in-memory session stores with KV or Durable Objects, debugging techniques for failed imports using wrangler dry-run and remote dev, bundle size optimization, and a production deployment checklist with staged rollout guidance.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://www.sitepoint.com/migrating-express-koa-cloudflare-workers-nodejs-compat>

## Questions this post answers

### How do I migrate an existing Express app to run on Cloudflare Workers?

Set compatibility_date in wrangler.toml to the minimum date enabling node:http and add nodejs_compat_v2 to compatibility_flags, then wrap the Express app with httpServerHandler from the cloudflare:workers module in a worker.js entry point instead of calling app.listen(). Move app.listen() into a separate server.js used only for local development, audit middleware for filesystem or native-addon dependencies, and replace in-memory sessions with KV or Durable Objects.

_daily.dev surfaces edge-migration guides like this for teams planning an Express-to-Workers move._

### Why does express-session fail on Cloudflare Workers and what should I use instead?

express-session defaults to in-memory storage, which breaks because each Workers request can execute in a different V8 isolate, losing session state between requests. The fix is to replace it with a KV-backed or Durable Objects-backed session store, validating the session ID format and writing to KV using ctx.waitUntil() rather than res.on('finish') to guarantee the write completes before the isolate terminates.

_Developers swapping stateful middleware for edge-native stores can track these patterns on daily.dev._

### Is bcrypt compatible with Cloudflare Workers, and what's the alternative?

Native bcrypt is not compatible with Cloudflare Workers because it relies on native C++ addons that cannot load in the V8 isolate environment. The pure-JavaScript bcryptjs library works but runs 3-10x slower at equivalent work factors, so on Workers it's recommended to keep the work factor at 8 or below to stay within the 50ms Bundled CPU time limit, or use the Web Crypto API's SubtleCrypto.deriveKey with PBKDF2 instead.

_Teams weighing native-addon replacements for edge runtimes can follow this kind of guidance on daily.dev._

## Similar posts on daily.dev

- [Introduction to Cloudflare Workers for Web Apps – Master.dev Blog](https://daily.dev/posts/introduction-to-cloudflare-workers-for-web-apps-master-dev-blog-9jviflkpb) · Frontend Masters · 0 upvotes · 0 comments
- [How to Deploy a Full-Stack Next.js App on Cloudflare Workers with GitHub Actions CI/CD](https://daily.dev/posts/how-to-deploy-a-full-stack-next-js-app-on-cloudflare-workers-with-github-actions-ci-cd-brfs1cbrn) · freeCodeCamp · 2 upvotes · 0 comments
- [Cloudflare Workers: your first serverless function](https://daily.dev/posts/cloudflare-workers-your-first-serverless-function-zkqoxjdgf) · Flavio Copes · 0 upvotes · 0 comments
- [How we rebuilt Cloudflare Workers’ module registry for Node.js compatibility](https://daily.dev/posts/how-we-rebuilt-cloudflare-workers-module-registry-for-node-js-compatibility-jqnzndbcb) · Cloudflare · 25 upvotes · 1 comments
- [Production at the Edge](https://daily.dev/posts/production-at-the-edge-ylvn9rvnh) · Flavio Copes · 0 upvotes · 0 comments

---

Tags: [#nodejs](https://daily.dev/tags/nodejs), [#cloudflare](https://daily.dev/tags/cloudflare), [#express](https://daily.dev/tags/express), [#edge-computing](https://daily.dev/tags/edge-computing)

[View this post on daily.dev](https://daily.dev/posts/migrating-express-and-koa-apps-to-cloudflare-workers-node-js-compatibility-production-guide-wiuwlhzj1)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Migrating Express and Koa Apps to Cloudflare Workers: Node.js Compatibility Production Guide","url":"https://daily.dev/posts/migrating-express-and-koa-apps-to-cloudflare-workers-node-js-compatibility-production-guide-wiuwlhzj1","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/migrating-express-and-koa-apps-to-cloudflare-workers-node-js-compatibility-production-guide-wiuwlhzj1"},"datePublished":"2026-07-15T21:21:45.259Z","dateModified":"2026-09-14T08:02:24.285Z","description":"A production migration guide for moving Express and Koa applications to Cloudflare Workers using the nodejs_compat_v2 flag introduced in 2025. Covers the...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/966df6782b9c5148b176792582440897?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/966df6782b9c5148b176792582440897?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"SitePoint","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"SitePoint","logo":"https://media.daily.dev/image/upload/t_logo,f_auto/v1/logos/sitepoint","url":"https://daily.dev/sources/sitepoint"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/migrating-express-and-koa-apps-to-cloudflare-workers-node-js-compatibility-production-guide-wiuwlhzj1","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"nodejs,cloudflare,express,edge-computing","timeRequired":"PT20M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"SitePoint","item":"https://daily.dev/sources/sitepoint"},{"@type":"ListItem","position":3,"name":"Migrating Express and Koa Apps to Cloudflare Workers: Node.js Compatibility Production Guide"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/migrating-express-and-koa-apps-to-cloudflare-workers-node-js-compatibility-production-guide-wiuwlhzj1#faq","mainEntity":[{"@type":"Question","name":"How do I migrate an existing Express app to run on Cloudflare Workers?","acceptedAnswer":{"@type":"Answer","text":"Set compatibility_date in wrangler.toml to the minimum date enabling node:http and add nodejs_compat_v2 to compatibility_flags, then wrap the Express app with httpServerHandler from the cloudflare:workers module in a worker.js entry point instead of calling app.listen(). Move app.listen() into a separate server.js used only for local development, audit middleware for filesystem or native-addon dependencies, and replace in-memory sessions with KV or Durable Objects. daily.dev surfaces edge-migration guides like this for teams planning an Express-to-Workers move."}},{"@type":"Question","name":"Why does express-session fail on Cloudflare Workers and what should I use instead?","acceptedAnswer":{"@type":"Answer","text":"express-session defaults to in-memory storage, which breaks because each Workers request can execute in a different V8 isolate, losing session state between requests. The fix is to replace it with a KV-backed or Durable Objects-backed session store, validating the session ID format and writing to KV using ctx.waitUntil() rather than res.on('finish') to guarantee the write completes before the isolate terminates. Developers swapping stateful middleware for edge-native stores can track these patterns on daily.dev."}},{"@type":"Question","name":"Is bcrypt compatible with Cloudflare Workers, and what's the alternative?","acceptedAnswer":{"@type":"Answer","text":"Native bcrypt is not compatible with Cloudflare Workers because it relies on native C++ addons that cannot load in the V8 isolate environment. The pure-JavaScript bcryptjs library works but runs 3-10x slower at equivalent work factors, so on Workers it's recommended to keep the work factor at 8 or below to stay within the 50ms Bundled CPU time limit, or use the Web Crypto API's SubtleCrypto.deriveKey with PBKDF2 instead. Teams weighing native-addon replacements for edge runtimes can follow this kind of guidance on daily.dev."}}]}
```

