Edge Runtime: What Breaks When You Leave Node.js
Edge runtimes aren't Node.js. No fs, no native modules, no TCP sockets, and strict CPU limits. Know the constraints before you deploy.
Edge runtimes (Cloudflare Workers, Vercel Edge Functions, Deno Deploy) run JavaScript
close to users for lower latency. But they're not Node.js. Move code to the edge without
understanding the constraints, and you'll hit cryptic errors: fs is not defined,
process is not a function, or worse—silent failures at runtime.
Why Edge Runtimes Are Different
Edge environments run on a stripped-down JavaScript runtime based on Web APIs (like browsers), not Node.js. They're designed for:
- Fast cold starts: Sub-millisecond startup, no heavy Node.js bootstrap
- Isolation: Each request runs in a sandboxed environment
- Global distribution: Code runs on hundreds of edge locations
The tradeoff: no filesystem, limited CPU time, restricted APIs.
What's NOT Available
1. Filesystem (fs)
import fs from 'fs'; // ❌ fs is not available
// Common patterns that break:
const config = fs.readFileSync('./config.json');
const template = fs.readFileSync('./template.html', 'utf-8');
fs.writeFileSync('./log.txt', data);
Edge functions are ephemeral and distributed—there's no persistent filesystem.
Cloudflare has recently added a virtual node:fs polyfill, but it's
read-only and limited to files bundled at build time.
Workarounds:
- Embed files at build time (import as string/JSON)
- Use KV storage, R2, or external APIs for dynamic data
- Fetch from URLs instead of reading from disk
2. Native Modules (C++ Addons)
// ❌ Native modules don't work
import bcrypt from 'bcrypt'; // Uses native bindings
import sharp from 'sharp'; // Image processing, native
import sqlite3 from 'sqlite3'; // Native SQLite bindingsAnything that compiles to native code won't run. Edge runtimes execute JavaScript or WebAssembly only.
Workarounds:
bcrypt→ Usebcryptjs(pure JS) or Web Crypto APIsharp→ Use@cloudflare/image-resizingor external servicessqlite3→ Use D1 (Cloudflare), Turso, or external databases
3. Long-Running Processes
// ❌ Will be killed
setInterval(() => {
checkForUpdates();
}, 60000);
// ❌ Exceeds CPU time limits
while (processingHugeDataset) {
// Edge functions have 10-50ms CPU limits (varies by platform)
}Edge functions are request-scoped. They start, handle a request, and terminate. Background processing, cron jobs, and long computations must happen elsewhere.
4. Node.js Globals
// ❌ Not available or different
process.env.MY_VAR // Use platform-specific env APIs
Buffer.from(data) // May need polyfill or use Uint8Array
__dirname // Doesn't exist
require() // ESM only in most edge runtimes
process is partially polyfilled in some runtimes but not fully
Node.js-compatible. Vercel Edge exposes process.env for environment
variables. Cloudflare uses a different binding system.
5. TCP/UDP Sockets
import net from 'net'; // ❌ No raw sockets
// Can't do:
const socket = net.createConnection({ port: 5432, host: 'db.example.com' });
// Most database drivers fail because they use TCP
import pg from 'pg'; // ❌ Uses net moduleEdge runtimes only support HTTP(S) outbound connections. Direct database connections over TCP are blocked.
Workarounds:
- Use HTTP-based database proxies (Neon, PlanetScale, Supabase)
- Cloudflare's Hyperdrive for connection pooling
- GraphQL/REST APIs instead of direct connections
What IS Available
Web Standard APIs
// ✅ All of these work
fetch('https://api.example.com/data');
new Request(url, options);
new Response(body, init);
new URL('https://example.com/path');
new Headers({ 'Content-Type': 'application/json' });
// Streams
new ReadableStream({ ... });
new WritableStream({ ... });
new TransformStream();
// Crypto
crypto.subtle.digest('SHA-256', data);
crypto.getRandomValues(new Uint8Array(16));
// Text encoding
new TextEncoder().encode('hello');
new TextDecoder().decode(bytes);
// Timers (with caveats)
setTimeout(fn, ms); // Works during request
await new Promise(r => setTimeout(r, 100));Partial Node.js Compatibility
Cloudflare Workers (with nodejs_compat flag) and Vercel Edge provide
partial Node.js API support:
// ✅ Often available (check platform docs)
import { Buffer } from 'buffer';
import { EventEmitter } from 'events';
import { createHash } from 'crypto'; // Subset of node:crypto
// May need compatibility flag
import path from 'path'; // Works in Cloudflare with nodejs_compatAlways verify against your specific platform's compatibility matrix. Partial support means some methods exist but others throw.
Dynamic Imports and eval()
// ❌ Runtime code execution blocked
eval('console.log("hello")');
new Function('return 42')();
import(dynamicPath); // May fail at runtimeFor security, edge runtimes restrict dynamic code execution. All code must be known at build time. This breaks some libraries that rely on runtime code generation.
Memory Limits
// ❌ Will exceed memory limits
const hugeArray = new Array(100_000_000).fill(0);
const bigBuffer = Buffer.alloc(256 * 1024 * 1024);
// Edge functions typically have 128MB limit
// Vercel Edge: 128MB
// Cloudflare Workers: 128MB (can be higher on paid plans)Process large data in chunks or offload to serverless functions with higher limits.
Detecting the Runtime
// Check if running on edge
function isEdgeRuntime(): boolean {
// Vercel Edge
if (typeof EdgeRuntime !== 'undefined') return true;
// Cloudflare Workers
if (typeof caches !== 'undefined' &&
typeof WebSocketPair !== 'undefined') return true;
// Deno Deploy
if (typeof Deno !== 'undefined') return true;
return false;
}
// Conditional logic
if (isEdgeRuntime()) {
// Use fetch-based approach
} else {
// Use Node.js fs/db approach
}Library Compatibility
Many npm packages assume Node.js. Check for edge-compatible alternatives:
// ❌ Node.js only → ✅ Edge compatible
bcrypt → bcryptjs, @noble/hashes
jsonwebtoken → jose
axios → native fetch
pg, mysql2 → @neondatabase/serverless, @planetscale/database
fs-extra → platform KV/R2 storage
winston, pino → console.log (or edge-specific loggers)Platform-Specific Quirks
Cloudflare Workers
- Bindings for KV, R2, D1, Queues replace Node.js equivalents
nodejs_compatflag enables more Node.js APIs- Request CPU time limit: 50ms (free) / 30s (paid)
Vercel Edge Functions
export const runtime = 'edge'in Next.js- Access env via
process.env - 25-second maximum execution time
Deno Deploy
- Deno APIs available (but not all)
- npm compatibility via
npm:specifiers - No
Deno.readFilefor local files
Key Takeaways
- No filesystem: Embed at build time or use cloud storage
- No native modules: Use pure JS alternatives or WASM
- No raw TCP: HTTP-based database connections only
- No long processes: Request-scoped execution with CPU limits
- Web APIs only: fetch, crypto, streams, URL—browser-like environment
- Always check your platform's specific compatibility before deploying
Advertisement
Explore these curated resources to deepen your understanding
Official Documentation
Tools & Utilities
Related Insights
Explore related edge cases and patterns
Advertisement