EdgeCases Logo
Feb 2026
Architecture
Expert
8 min read

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-runtime
cloudflare-workers
vercel-edge
nodejs
serverless
javascript

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 bindings

Anything that compiles to native code won't run. Edge runtimes execute JavaScript or WebAssembly only.

Workarounds:

  • bcrypt → Use bcryptjs (pure JS) or Web Crypto API
  • sharp → Use @cloudflare/image-resizing or external services
  • sqlite3 → 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 module

Edge 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_compat

Always 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 runtime

For 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_compat flag 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.readFile for 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

Related Insights

Explore related edge cases and patterns

Browser APIs
Surface
Intersection Observer rootMargin: The Scroll Container Trap
6 min
TypeScript
Expert
TypeScript Template Literal Types: When Clever Types Explode
8 min

Advertisement