home / skills / secondsky / claude-skills / cloudflare-workers-migration

This skill helps migrate existing workloads to Cloudflare Workers, simplifying porting from Lambda, Vercel, and Express with edge-ready compatibility.

npx playbooks add skill secondsky/claude-skills --skill cloudflare-workers-migration

Review the files below or copy the command above to add this skill to your agents.

Files (10)
SKILL.md
5.1 KB
---
name: workers-migration
description: Migrate to Cloudflare Workers from AWS Lambda, Vercel, Express, and Node.js. Use when porting existing applications to the edge, adapting serverless functions, or resolving Node.js API compatibility issues.
version: 1.0.0
---

# Workers Migration Guide

Migrate existing applications to Cloudflare Workers from various platforms.

## Migration Decision Tree

```
What are you migrating from?
├── AWS Lambda
│   └── Node.js handler? → Lambda adapter pattern
│   └── Python? → Consider Python Workers
│   └── Container/custom runtime? → May need rewrite
├── Vercel/Next.js
│   └── API routes? → Minimal changes with adapter
│   └── Full Next.js app? → Use OpenNext adapter
│   └── Middleware? → Direct Workers equivalent
├── Express/Node.js
│   └── Simple API? → Hono (similar API)
│   └── Complex middleware? → Gradual migration
│   └── Heavy node: usage? → Compatibility layer
└── Other Edge (Deno Deploy, Fastly)
    └── Standard Web APIs? → Minimal changes
    └── Platform-specific? → Targeted rewrites
```

## Platform Comparison

| Feature | Workers | Lambda | Vercel | Express |
|---------|---------|--------|--------|---------|
| **Cold Start** | ~0ms | 100-500ms | 10-100ms | N/A |
| **CPU Limit** | 50ms/10ms | 15 min | 10s | None |
| **Memory** | 128MB | 10GB | 1GB | System |
| **Max Response** | 6MB (stream unlimited) | 6MB | 4.5MB | None |
| **Global Edge** | 300+ PoPs | Regional | ~20 PoPs | Manual |
| **Node.js APIs** | Partial | Full | Full | Full |

## Top 10 Migration Errors

| Error | From | Cause | Solution |
|-------|------|-------|----------|
| `fs is not defined` | Lambda/Express | File system access | Use KV/R2 for storage |
| `Buffer is not defined` | Node.js | Node.js globals | Import from `node:buffer` |
| `process.env undefined` | All | Env access pattern | Use `env` parameter |
| `setTimeout not returning` | Lambda | Async patterns | Use `ctx.waitUntil()` |
| `require() not found` | Express | CommonJS | Convert to ESM imports |
| `Exceeded CPU time` | All | Long computation | Chunk or use DO |
| `body already consumed` | Express | Request body | Clone before read |
| `Headers not iterable` | Lambda | Headers API | Use Headers constructor |
| `crypto.randomBytes` | Node.js | Node crypto | Use `crypto.getRandomValues` |
| `Cannot find module` | All | Missing polyfill | Check Workers compatibility |

## Quick Migration Patterns

### AWS Lambda Handler

```typescript
// Before: AWS Lambda
export const handler = async (event, context) => {
  const body = JSON.parse(event.body);
  return {
    statusCode: 200,
    body: JSON.stringify({ message: 'Hello' }),
  };
};

// After: Cloudflare Workers
export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const body = await request.json();
    return Response.json({ message: 'Hello' });
  },
};
```

### Express Middleware

```typescript
// Before: Express
app.use((req, res, next) => {
  if (!req.headers.authorization) {
    return res.status(401).json({ error: 'Unauthorized' });
  }
  next();
});

// After: Hono Middleware
app.use('*', async (c, next) => {
  if (!c.req.header('Authorization')) {
    return c.json({ error: 'Unauthorized' }, 401);
  }
  await next();
});
```

### Environment Variables

```typescript
// Before: Node.js
const apiKey = process.env.API_KEY;

// After: Workers
export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const apiKey = env.API_KEY;
    // ...
  },
};
```

## Node.js Compatibility

Workers support many Node.js APIs via compatibility flags:

```jsonc
// wrangler.jsonc
{
  "compatibility_flags": ["nodejs_compat_v2"],
  "compatibility_date": "2024-12-01"
}
```

**Supported with nodejs_compat_v2:**
- `crypto` (most methods)
- `buffer` (Buffer class)
- `util` (promisify, types)
- `stream` (Readable, Writable)
- `events` (EventEmitter)
- `path` (all methods)
- `string_decoder`
- `assert`

**Not Supported (need alternatives):**
- `fs` → Use R2/KV
- `child_process` → Not possible
- `cluster` → Not applicable
- `dgram` → Not supported
- `net` → Use fetch/WebSocket
- `tls` → Handled by platform

## When to Load References

| Reference | Load When |
|-----------|-----------|
| `references/lambda-migration.md` | Migrating AWS Lambda functions |
| `references/vercel-migration.md` | Migrating from Vercel/Next.js |
| `references/express-migration.md` | Migrating Express/Node.js apps |
| `references/node-compatibility.md` | Node.js API compatibility issues |

## Migration Checklist

1. **Analyze Dependencies**: Check for unsupported Node.js APIs
2. **Convert to ESM**: Replace require() with import
3. **Update Env Access**: Use env parameter instead of process.env
4. **Replace File System**: Use R2/KV for storage
5. **Handle Async**: Use ctx.waitUntil() for background tasks
6. **Test Locally**: Verify with wrangler dev
7. **Performance Test**: Ensure CPU limits aren't exceeded

## See Also

- `workers-runtime-apis` - Available APIs in Workers
- `workers-performance` - Optimization techniques
- `cloudflare-worker-base` - Basic Workers setup

Overview

This skill helps teams migrate existing applications to Cloudflare Workers from AWS Lambda, Vercel/Next.js, Express, and plain Node.js. It provides practical patterns, a decision tree, common error fixes, and a migration checklist to make porting serverless functions and Node APIs to the edge predictable and production-ready.

How this skill works

The skill inspects source platform characteristics and recommends concrete rewrites or adapter patterns (Lambda handler → Workers fetch, Express middleware → Hono, Vercel adapters, etc.). It highlights Node.js compatibility flags, identifies unsupported APIs, and maps platform-specific behaviors to Workers equivalents like R2/KV, env bindings, and ctx.waitUntil().

When to use it

  • Porting AWS Lambda functions or Lambda-based microservices to the edge
  • Migrating Vercel/Next.js API routes or replacing middleware with edge equivalents
  • Adapting Express/Node.js APIs to a Workers-compatible framework (Hono)
  • Resolving Node.js API compatibility issues or polyfill needs
  • Optimizing global performance by moving logic to Cloudflare’s PoPs

Best practices

  • Analyze dependencies first: identify fs, child_process, net, and other unsupported APIs
  • Convert CommonJS to ESM imports to avoid require() issues in Workers
  • Use env bindings (env.PARAM) instead of process.env inside fetch handlers
  • Replace filesystem needs with R2 or KV and large compute with durable workers or external services
  • Enable nodejs_compat_v2 and set compatibility_date for supported Node APIs when needed
  • Test locally with wrangler dev and run performance checks to respect CPU limits

Example use cases

  • Convert an AWS Lambda JSON API to a Cloudflare Worker fetch handler for global low-latency responses
  • Migrate Express middleware to Hono middleware to preserve auth and request handling patterns
  • Replace Vercel API routes with OpenNext or lightweight adapters for edge-native deployment
  • Resolve missing Node globals like Buffer and crypto by enabling compat flags or using Web Crypto
  • Move file-backed assets to R2 and use KV for configuration and small state storage

FAQ

Can I keep using my existing Node modules?

Many modules work under nodejs_compat_v2, but modules using fs, child_process, net, or native binaries often need replacement or refactor.

How do I access environment variables in Workers?

Expose values as env bindings and read them via the env parameter in your fetch handler rather than process.env.