Best npm Packages for Edge Runtimes in 2026
Not every npm package works on edge runtimes. Edge environments use the Fetch API instead of Node.js's http module, lack access to the filesystem, and have CPU time limits (10-50ms on Cloudflare Workers). The packages that work best are those built on Web Standards — and in 2026, that list has grown substantially as npm package authors have added edge compatibility.
TL;DR
The edge runtime npm ecosystem in 2026 centers on a few key categories: routing (Hono — 2M downloads, works on 9+ runtimes), storage (Cloudflare's D1, KV, R2 client libraries), validation (Zod works edge-natively, so does Valibot), and utilities (ioredis has alternatives, most date libraries work). Avoid packages that require fs, child_process, net, or Node.js-only streams — they'll fail at the edge.
Key Takeaways
- Hono: 2M weekly downloads, <14 kB, the standard router for edge runtimes
wrangler: Cloudflare's CLI + local emulation for D1, KV, R2, Durable Objects@cloudflare/workers-types: TypeScript types for Workers APIs (KV, D1, R2, etc.)@cloudflare/vitest-pool-workers: Run tests inside the actual Workers runtime- Zod: Fully edge-compatible (no Node.js dependencies)
- Packages to avoid:
express,axios(use native fetch),fs-extra,bcrypt(use SubtleCrypto) - Web Crypto API: Use
crypto.subtleinstead of Node.jscryptomodule
The Edge Runtime Constraint
Edge runtimes implement the WinterCG spec — a subset of Web APIs without Node.js-specific APIs:
// Available in edge runtimes:
fetch() // HTTP requests
Request // Web Fetch API
Response // Web Fetch API
URL // URL parsing
URLSearchParams // Query string
Headers // HTTP headers
crypto.subtle // Web Crypto (NOT Node.js crypto)
TextEncoder // Text encoding
TextDecoder // Text decoding
ReadableStream // Streaming
// NOT available in edge runtimes:
fs // No filesystem
child_process // No process spawning
net // No raw TCP
node:crypto // No Node.js crypto (use crypto.subtle)
Buffer // Limited (polyfill available in Workers)
Routing: Hono
Package: hono
Weekly downloads: 2M
GitHub stars: 23K
Hono is the standard framework for edge runtimes. It's built on Web Standards, has zero platform-specific dependencies, and works on Cloudflare Workers, Deno Deploy, Vercel Edge, AWS Lambda, Bun, and Node.js.
npm install hono
// Works identically on Cloudflare Workers, Deno Deploy, and Node.js
import { Hono } from 'hono';
import { cors } from 'hono/cors';
import { logger } from 'hono/logger';
import { validator } from 'hono/validator';
import { zValidator } from '@hono/zod-validator';
import { z } from 'zod';
const app = new Hono<{ Bindings: Env }>();
app.use('*', cors());
app.use('*', logger());
const userSchema = z.object({
name: z.string().min(2),
email: z.string().email(),
});
app.post('/api/users',
zValidator('json', userSchema),
async (c) => {
const data = c.req.valid('json');
const { meta } = await c.env.DB
.prepare('INSERT INTO users (name, email) VALUES (?, ?)')
.bind(data.name, data.email)
.run();
return c.json({ id: meta.last_row_id }, 201);
}
);
export default app;
Cloudflare Platform Packages
wrangler — The Essential CLI
npm install -D wrangler
# Local development with D1, KV, R2 emulation
wrangler dev
# Deploy to Cloudflare Workers
wrangler deploy
# Manage KV namespaces
wrangler kv namespace create CACHE
wrangler kv key put --binding=CACHE "key" "value"
# Create D1 database
wrangler d1 create my-database
wrangler d1 execute my-database --file=schema.sql
# Tail real-time logs from production
wrangler tail
# Generate TypeScript types from wrangler.toml
wrangler types
@cloudflare/workers-types — TypeScript Types
npm install -D @cloudflare/workers-types
// tsconfig.json
{
"compilerOptions": {
"types": ["@cloudflare/workers-types"]
}
}
// Or use wrangler types (preferred in 2026):
// Creates worker-configuration.d.ts with your specific bindings
// Now TypeScript knows about all Workers APIs:
async function handler(request: Request, env: Env): Promise<Response> {
// env.KV is typed as KVNamespace
const value = await env.KV.get('my-key');
// env.DB is typed as D1Database
const users = await env.DB.prepare('SELECT * FROM users').all();
// env.BUCKET is typed as R2Bucket
const object = await env.BUCKET.get('image.png');
return Response.json(users.results);
}
@cloudflare/vitest-pool-workers — Test in the Real Runtime
npm install -D @cloudflare/vitest-pool-workers vitest
// vitest.config.ts
import { defineWorkersConfig } from '@cloudflare/vitest-pool-workers/config';
export default defineWorkersConfig({
test: {
poolOptions: {
workers: {
wrangler: { configPath: './wrangler.toml' },
},
},
},
});
// api.test.ts — runs inside the actual Workers runtime
import { SELF } from 'cloudflare:test';
import { describe, it, expect } from 'vitest';
describe('API', () => {
it('returns users', async () => {
// SELF is your Worker — real D1, KV, R2 bindings
const response = await SELF.fetch('http://localhost/api/users');
expect(response.status).toBe(200);
const users = await response.json();
expect(Array.isArray(users)).toBe(true);
});
});
Tests run in the actual Workers runtime with real bindings — not a Node.js simulation.
@cloudflare/d1 and Database Patterns
// D1 (SQLite at the edge) — no separate client package needed
// Access via the env binding:
interface Env {
DB: D1Database;
}
export default {
async fetch(request: Request, env: Env) {
// Query
const users = await env.DB
.prepare('SELECT * FROM users WHERE active = ?')
.bind(true)
.all();
// Insert
const { meta } = await env.DB
.prepare('INSERT INTO users (name, email) VALUES (?, ?)')
.bind('Alice', 'alice@example.com')
.run();
// Batch queries
const results = await env.DB.batch([
env.DB.prepare('INSERT INTO users (name) VALUES (?)').bind('Alice'),
env.DB.prepare('INSERT INTO users (name) VALUES (?)').bind('Bob'),
]);
return Response.json({ users: users.results });
},
};
Edge-Compatible Libraries
Validation: Zod and Valibot
npm install zod
# or:
npm install valibot # Smaller bundle, fully edge-compatible
Both work natively in edge runtimes — no Node.js dependencies.
HTTP Client: Native Fetch
// DON'T use axios in edge runtimes (node http module dependency)
// import axios from 'axios'; // May fail on Workers
// DO use native fetch — available in all edge runtimes:
const response = await fetch('https://api.example.com/data', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ key: 'value' }),
});
const data = await response.json();
Cryptography: Web Crypto API
// DON'T use Node.js crypto:
// import crypto from 'crypto'; // Not available on edge
// DO use Web Crypto:
async function hashPassword(password: string): Promise<string> {
const encoder = new TextEncoder();
const data = encoder.encode(password);
const hash = await crypto.subtle.digest('SHA-256', data);
return btoa(String.fromCharCode(...new Uint8Array(hash)));
}
// JWT verification with Web Crypto:
async function verifyJWT(token: string, secret: string): Promise<boolean> {
const key = await crypto.subtle.importKey(
'raw',
new TextEncoder().encode(secret),
{ name: 'HMAC', hash: 'SHA-256' },
false,
['verify']
);
// ... verify signature
}
ORM: Drizzle with D1
npm install drizzle-orm
npm install -D drizzle-kit
// schema.ts
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core';
export const users = sqliteTable('users', {
id: integer('id').primaryKey({ autoIncrement: true }),
name: text('name').notNull(),
email: text('email').notNull().unique(),
});
// index.ts
import { drizzle } from 'drizzle-orm/d1';
import { users } from './schema';
import { eq } from 'drizzle-orm';
export default {
async fetch(request: Request, env: Env) {
const db = drizzle(env.DB);
const allUsers = await db.select().from(users);
const user = await db.select()
.from(users)
.where(eq(users.email, 'alice@example.com'))
.get();
return Response.json(allUsers);
}
};
Date Libraries
npm install date-fns # Fully edge-compatible
// date-fns works in edge runtimes (no Node.js dependencies)
import { format, addDays, differenceInDays } from 'date-fns';
const formatted = format(new Date(), 'yyyy-MM-dd');
What NOT to Use in Edge Runtimes
// ❌ Node.js http module — use fetch instead
import http from 'http';
// ❌ Express — not edge-compatible
import express from 'express';
// ❌ Axios — depends on Node.js http (though newer versions have fetch mode)
import axios from 'axios';
// ❌ bcrypt — uses native bindings
import bcrypt from 'bcrypt';
// ✅ Use: bcryptjs (pure JS) or Web Crypto
// ❌ sharp — requires native bindings
import sharp from 'sharp';
// ✅ Use: Cloudflare Images API or a separate service
// ❌ node:crypto (import via node: protocol)
import crypto from 'node:crypto';
// ✅ Use: crypto.subtle (Web Crypto API)
// ❌ fs — no filesystem in edge runtimes
import fs from 'fs';
// ✅ Use: R2 for file storage, KV for small data
Edge Compatibility Checklist
Before using any npm package on an edge runtime:
# Check if package has "edge" in keywords or README
# Check for Node.js-specific imports in source
# Common red flags:
# - import { createServer } from 'http'
# - import { readFile } from 'fs'
# - import { exec } from 'child_process'
# - Mentions "Node.js required" in README
# Good signs:
# - "Works with Cloudflare Workers" in README
# - Uses only Web Standards APIs
# - Zero dependencies or all web-standard deps
# - "edge-runtime" package.json exports condition
The 2026 Edge Stack
// wrangler.toml
name = "my-api"
main = "src/index.ts"
compatibility_date = "2024-01-01"
compatibility_flags = ["nodejs_compat"] // Enable Node.js compat
[[d1_databases]]
binding = "DB"
database_name = "my-database"
database_id = "..."
[[kv_namespaces]]
binding = "CACHE"
id = "..."
[[r2_buckets]]
binding = "BUCKET"
bucket_name = "my-assets"
// package.json
{
"dependencies": {
"hono": "^4.x", // Routing
"drizzle-orm": "^0.x", // ORM for D1
"zod": "^3.x", // Validation
"@hono/zod-validator": "^0.x" // Hono + Zod integration
},
"devDependencies": {
"wrangler": "^3.x",
"@cloudflare/workers-types": "^4.x",
"@cloudflare/vitest-pool-workers": "^0.x",
"drizzle-kit": "^0.x",
"vitest": "^2.x"
}
}
Compare edge-compatible package downloads on PkgPulse.
See the live comparison
View best edge runtime npm packages on PkgPulse →