뒤로가기
Edge Runtime에서 돌아가는 것과 안 되는 것

May 26, 2025

nextjsdevopsfrontend

Edge Runtime이 좋다는 건 알겠다. 사용자와 가까운 CDN 엣지 노드에서 코드가 실행되니까 레이턴시가 줄어든다. Cold start도 Node.js 서버리스 함수보다 빠르다. 그래서 API Route 하나를 Edge로 바꿔봤다가, 생각보다 많은 것이 안 되는 걸 알았다.

Edge Runtime ≠ Node.js#

Edge Runtime은 Node.js가 아니다. V8 엔진 위에서 돌아가지만, 브라우저의 Web API에 가까운 환경이다. Node.js의 코어 모듈을 쓸 수 없다.

Next.js에서 Edge Runtime을 쓰려면:

typescript
// app/api/hello/route.ts
export const runtime = 'edge';

export async function GET() {
  return new Response('Hello from Edge');
}

이 한 줄(export const runtime = 'edge')이 실행 환경을 완전히 바꾼다.

안 되는 것들#

1. Node.js 네이티브 모듈

fs, path, crypto의 일부, child_process, net — 전부 안 된다. 파일 시스템이 없으니 fs.readFile은 당연히 안 되고, path.resolve도 안 된다.

typescript
// Edge에서 이건 에러
import fs from 'fs';
import path from 'path';

2. 대부분의 npm 패키지

내부적으로 Node.js API를 쓰는 패키지는 다 안 된다. 놀라운 건 꽤 많은 패키지가 어딘가에서 Node.js API를 쓰고 있다는 것이다.

실제로 겪은 사례:

  • jsonwebtoken — 내부에서 Node.js crypto 사용. 대신 jose 라이브러리를 써야 한다
  • bcrypt — C++ 네이티브 바인딩. 대신 bcryptjs(순수 JS)를 써야 한다
  • sharp — 이미지 처리. Edge에서 동작하지 않음
typescript
// Node.js Runtime
import jwt from 'jsonwebtoken';
const token = jwt.sign(payload, secret);

// Edge Runtime
import { SignJWT } from 'jose';
const token = await new SignJWT(payload)
  .setProtectedHeader({ alg: 'HS256' })
  .sign(new TextEncoder().encode(secret));

jose는 Web Crypto API를 기반으로 만들어져서 Edge에서 잘 동작한다.

3. 실행 시간 제한

Vercel Edge Functions는 기본 30초 타임아웃이 있고, Cloudflare Workers 무료 플랜은 10ms CPU 시간 제한이 있다. 무거운 연산이나 느린 외부 API를 호출하면 타임아웃에 걸린다.

4. 전역 상태/메모리

Edge 함수는 요청마다 새로 실행될 수 있고, 같은 인스턴스가 재활용될 수도 있다. 전역 변수에 의존하면 예측 불가능한 동작이 된다. 인메모리 캐시? 안 된다.

돌아가는 것들#

1. Web 표준 API

fetch, Request, Response, URL, URLSearchParams, Headers, TextEncoder, TextDecoder, crypto.subtle — Web 표준 API는 다 된다.

typescript
export const runtime = 'edge';

export async function GET(request: Request) {
  const url = new URL(request.url);
  const query = url.searchParams.get('q');

  const response = await fetch(`https://api.example.com/search?q=${query}`);
  const data = await response.json();

  return Response.json(data, {
    headers: { 'Cache-Control': 'public, max-age=60' },
  });
}

2. KV/D1 같은 엣지 스토리지

Cloudflare의 KV, D1, R2 같은 엣지 네이티브 스토리지는 당연히 잘 동작한다. Vercel도 Edge Config, KV를 제공한다.

typescript
// Vercel KV
import { kv } from '@vercel/kv';

export const runtime = 'edge';

export async function GET(request: Request) {
  const cached = await kv.get('popular-posts');
  if (cached) return Response.json(cached);

  const posts = await fetchPopularPosts();
  await kv.set('popular-posts', posts, { ex: 300 }); // 5분 캐시
  return Response.json(posts);
}

언제 Edge를 쓰고, 언제 Node.js를 쓰나#

모든 걸 Edge로 바꿀 필요는 없다. 오히려 대부분의 API Route는 Node.js Runtime이 맞다.

Edge가 적합한 경우:

  • 인증 토큰 검증 (미들웨어)
  • 리다이렉트/리라이트 로직
  • A/B 테스트 분기
  • 지역 기반 콘텐츠 제공
  • 단순한 API 프록시

Node.js가 적합한 경우:

  • 데이터베이스 직접 연결 (대부분의 DB 드라이버가 Node.js 전용)
  • 파일 처리
  • 무거운 연산
  • Node.js 전용 라이브러리에 의존하는 로직

경험적으로, 미들웨어는 거의 항상 Edge가 맞고, API Route는 대부분 Node.js가 안전하다. Edge Runtime의 제약을 이해하고 적재적소에 쓰는 게 포인트다. 전부 Edge로 가겠다는 건 욕심이다.