Edge runtime cheatsheet.

What is edge

V8-based runtime, deployed globally close to users. Much faster cold starts than Node.js Lambdas. Limited APIs.

Trade-offs:

  • ✅ Cold start ~5ms.
  • ✅ Geographic distribution.
  • ✅ Smaller bundle = faster.
  • ❌ No fs, child_process, net, native modules.
  • ❌ Limited memory (~128MB on Vercel).
  • ❌ Different fetch/Buffer semantics.

Opting into edge

Per route:

// app/api/foo/route.ts
export const runtime = "edge";

export async function GET() {
  return Response.json({ hello: "edge" });
}

Per page:

// app/page.tsx
export const runtime = "edge";

Middleware is always edge (default).

What works on edge

  • fetch
  • Request, Response, URL, Headers, FormData
  • Web Crypto (crypto.subtle)
  • TextEncoder / TextDecoder
  • setTimeout, setInterval
  • console, Math, Date, JSON
  • Standard JS

What doesn’t work:

  • fs (no filesystem)
  • net, dgram, child_process
  • Native node modules (sharp, etc)
  • require() of CommonJS (use ESM)
  • Most ORMs that use TCP — Prisma needs Data Proxy / Accelerate

Auth on edge

import { jwtVerify } from "jose";

const secret = new TextEncoder().encode(process.env.AUTH_SECRET);

export const runtime = "edge";

export async function GET(req: Request) {
  const token = req.headers.get("authorization")?.replace("Bearer ", "");
  if (!token) return new Response("401", { status: 401 });
  
  try {
    const { payload } = await jwtVerify(token, secret);
    return Response.json({ user: payload });
  } catch {
    return new Response("401", { status: 401 });
  }
}

jose works on edge. jsonwebtoken does not (uses Node crypto).

Database from edge

Native TCP doesn’t work. Options:

HTTP-based databases:

  • Neon (Postgres serverless driver)
  • PlanetScale (HTTP API)
  • Upstash Redis (REST)
  • Turso (libSQL HTTP)
import { neon } from "@neondatabase/serverless";

export const runtime = "edge";

const sql = neon(process.env.DATABASE_URL!);

export async function GET() {
  const rows = await sql`SELECT * FROM users LIMIT 10`;
  return Response.json(rows);
}

Prisma + Accelerate:

import { PrismaClient } from "@prisma/client";
import { withAccelerate } from "@prisma/extension-accelerate";

const db = new PrismaClient().$extends(withAccelerate());

Geolocation

// Vercel
export const runtime = "edge";

export async function GET(req: NextRequest) {
  const country = req.headers.get("x-vercel-ip-country");
  const city = req.headers.get("x-vercel-ip-city");
  return Response.json({ country, city });
}

Or use geolocation(req):

import { geolocation } from "@vercel/functions";

const { country, city, region } = geolocation(req);

Streaming responses

export const runtime = "edge";

export async function GET() {
  const encoder = new TextEncoder();
  const stream = new ReadableStream({
    async start(controller) {
      for (let i = 0; i < 10; i++) {
        controller.enqueue(encoder.encode(`event: ${i}\n\n`));
        await new Promise((r) => setTimeout(r, 200));
      }
      controller.close();
    },
  });
  
  return new Response(stream, {
    headers: { "Content-Type": "text/event-stream" },
  });
}

Edge is great for streaming (low latency).

OG images on edge

// app/posts/[id]/opengraph-image.tsx
import { ImageResponse } from "next/og";

export const runtime = "edge";
export const size = { width: 1200, height: 630 };

export default async function OG({ params }) {
  return new ImageResponse(<div>...</div>, { ...size });
}

Fast generation at edge, cached at CDN.

LLM streaming

export const runtime = "edge";

import { OpenAI } from "openai";

export async function POST(req: Request) {
  const { messages } = await req.json();
  const openai = new OpenAI();
  const stream = await openai.chat.completions.create({
    model: "gpt-4",
    messages,
    stream: true,
  });
  
  const encoder = new TextEncoder();
  return new Response(
    new ReadableStream({
      async start(controller) {
        for await (const chunk of stream) {
          const text = chunk.choices[0]?.delta?.content ?? "";
          controller.enqueue(encoder.encode(text));
        }
        controller.close();
      },
    }),
    { headers: { "Content-Type": "text/plain" } },
  );
}

Edge config (Vercel)

Read-only fast KV for feature flags, redirects, etc:

import { get } from "@vercel/edge-config";

export const runtime = "edge";

export async function GET() {
  const flag = await get("featureX");
  return Response.json({ flag });
}

Reads in ~1ms.

When NOT to use edge

  • Heavy CPU work — limited memory and timeout.
  • Native node deps (sharp, ffmpeg, etc).
  • TCP-based databases without HTTP wrappers.
  • Long-running requests (limits apply).

Common mistakes

  • Importing a Node-only library → build fails.
  • Buffer use → undefined on edge.
  • process.env not set in edge — verify available vars.
  • TCP DB without HTTP proxy → connection error.
  • Forgetting runtime = "edge" declaration.

Read this next

If you want my edge + LLM streaming patterns, they’re at rajpoot.dev .


Building something AI-, backend-, or data-heavy and want a second pair of eyes? I do consulting and freelance work — see my projects and ways to reach me at rajpoot.dev .