Next.js에는 애플리케이션에서 선택해서 사용할 수 있는 두 가지 서버 런타임이 준비되어 있어요:
💡 강사의 보충 설명: > '런타임(Runtime)'이란 코드가 실행되는 환경을 말해요. Node.js 런타임은 파일 시스템(
fs) 접근처럼 서버 컴퓨터가 할 수 있는 모든 무거운 작업을 다 할 수 있죠. 반면에 Edge 런타임은 전 세계에 퍼져 있는 CDN(Content Delivery Network) 노드, 즉 사용자와 가장 가까운 '가장자리(Edge)'에서 실행되는 아주 가벼운 환경을 말해요. 너무 가벼워야 하니까 무거운 Node.js 기능들은 다 덜어내고, 웹 표준 API들만 빠르게 실행하도록 만들어진 거랍니다!
💡 강사의 보충 설명:
ISR은 백그라운드에서 페이지를 미리 렌더링해서 파일로 저장해두는 기능인데, Edge 런타임은 그 자체로 파일 시스템이 없는 가벼운 컴퓨팅 환경이라서 ISR을 쓸 수가 없어요. 대신 스트리밍 기능은 아주 강력합니다. 특히 나중에 외부 API와 통신하여 텍스트를 생성하는 AI 문서 번역 기능 같은 포트폴리오를 기획하신다면, 이 엣지 환경에서 응답 스트리밍(Streaming)을 활용해 글자가 타자 치듯 실시간으로 나타나게 만드는 것이 핵심 기술이 될 거예요!
엣지 런타임은 아래와 같은 웹 표준 API들을 기본적으로 지원합니다:
| API | 설명 (Description) |
|---|---|
Blob | 바이너리 데이터 객체(blob)를 나타냅니다. |
fetch | 외부 리소스를 가져옵니다. (비동기 네트워크 통신) |
FetchEvent | fetch 이벤트를 나타냅니다. |
File | 파일(file) 데이터를 나타냅니다. |
FormData | HTML 폼(form) 데이터를 나타냅니다. |
Headers | HTTP 요청/응답 헤더를 다룹니다. |
Request | HTTP 요청(Request) 자체를 객체로 나타냅니다. |
Response | HTTP 응답(Response) 자체를 객체로 나타냅니다. |
URLSearchParams | URL의 쿼리 매개변수(?key=value 등)를 다룹니다. |
WebSocket | 실시간 양방향 통신을 위한 웹소켓 연결을 나타냅니다. |
| API | 설명 (Description) |
|---|---|
atob | Base64로 인코딩된 문자열을 디코딩(해독)합니다. |
btoa | 일반 문자열을 Base64 형식으로 인코딩(암호화)합니다. |
TextDecoder | Uint8Array 바이트 배열을 문자열로 디코딩합니다. |
TextDecoderStream | 스트림 데이터를 위한 체이닝 가능한 디코더입니다. |
TextEncoder | 문자열을 Uint8Array 바이트 배열로 인코딩합니다. |
TextEncoderStream | 스트림 데이터를 위한 체이닝 가능한 인코더입니다. |
| API | 설명 (Description) |
|---|---|
ReadableStream | 읽을 수 있는 데이터 스트림을 나타냅니다. |
ReadableStreamBYOBReader | ReadableStream을 읽기 위한 BYOB 리더기입니다. |
ReadableStreamDefaultReader | ReadableStream의 기본 리더기를 나타냅니다. |
TransformStream | 데이터를 변환(Transform)하는 스트림을 나타냅니다. |
WritableStream | 쓸 수 있는 데이터 스트림을 나타냅니다. |
WritableStreamDefaultWriter | WritableStream의 기본 라이터(작성기)를 나타냅니다. |
| API | 설명 (Description) |
|---|---|
crypto | 플랫폼에서 제공하는 암호화 기능에 접근할 수 있게 해줍니다. |
CryptoKey | 암호화 키(Key)를 나타냅니다. |
SubtleCrypto | 해싱(hashing), 서명, 암호화, 복호화 같은 일반적인 저수준 암호화 기능에 접근할 수 있게 해줍니다. |
이 부분은 자바스크립트를 쓰면서 한 번쯤 보셨을 법한 아주 기본적인 내장 객체와 함수들이에요.
| API | 설명 (Description) |
|---|---|
AbortController | 원할 때 언제든지 하나 이상의 DOM 요청이나 비동기 작업을 중단(Abort)할 수 있게 해줍니다. |
Array | 배열을 나타냅니다. |
ArrayBuffer | 고정된 길이의 원시 바이너리 데이터 버퍼를 나타냅니다. |
Atomics | 정적 메서드 형태로 원자적(atomic) 연산을 제공합니다. |
BigInt | 임의 정밀도를 가진 정수를 나타냅니다. (엄청 큰 숫자 다룰 때 써요!) |
BigInt64Array | 64비트 부호 있는 정수의 형식화된 배열입니다. |
BigUint64Array | 64비트 부호 없는 정수의 형식화된 배열입니다. |
Boolean | true 또는 false 두 가지 값을 가지는 논리적 요소를 나타냅니다. |
clearInterval | setInterval()로 설정했던 반복 작업을 취소합니다. |
clearTimeout | setTimeout()으로 설정했던 타이머 작업을 취소합니다. |
console | 브라우저나 서버의 디버깅 콘솔 기능에 접근합니다. |
DataView | ArrayBuffer의 데이터를 읽고 쓰기 위한 저수준 뷰를 제공합니다. |
Date | 플랫폼에 종속되지 않는 형식으로 특정 순간의 시간 데이터를 나타냅니다. |
decodeURI | encodeURI 등으로 인코딩된 전체 URI를 다시 디코딩합니다. |
decodeURIComponent | encodeURIComponent 등으로 인코딩된 URI의 특정 구성 요소를 디코딩합니다. |
DOMException | DOM에서 발생하는 에러를 나타냅니다. |
encodeURI | 전체 URI에서 특정 문자들을 UTF-8 인코딩을 나타내는 이스케이프 시퀀스로 변환하여 인코딩합니다. |
encodeURIComponent | URI의 특정 구성 요소에서 문자들을 변환하여 인코딩합니다. |
Error | 코드 실행이나 속성 접근 시 발생하는 기본 에러 객체입니다. |
EvalError | 전역 함수 eval()과 관련해서 발생하는 에러입니다. |
Float32Array | 32비트 부동소수점 숫자의 형식화된 배열입니다. |
Float64Array | 64비트 부동소수점 숫자의 형식화된 배열입니다. |
Function | 함수 객체 자체를 나타냅니다. |
Infinity | 수학적인 무한대 값을 나타냅니다. |
Int8Array | 8비트 부호 있는 정수의 배열입니다. |
Int16Array | 16비트 부호 있는 정수의 배열입니다. |
Int32Array | 32비트 부호 있는 정수의 배열입니다. |
Intl | 국제화(다국어 처리) 및 지역화 기능에 접근할 수 있게 해줍니다. |
isFinite | 어떤 값이 유한한 숫자인지 판별합니다. |
isNaN | 어떤 값이 NaN (Not-A-Number, 숫자가 아님)인지 판별합니다. |
JSON | 자바스크립트 값을 JSON 형식으로 변환(stringify)하거나 그 반대로 파싱(parse)하는 기능을 제공합니다. |
Map | 키와 값의 쌍으로 이루어진 컬렉션이며, 각 키는 고유합니다. |
Math | 수학적인 함수와 상수들에 접근할 수 있게 해줍니다. |
Number | 숫자 값을 나타내는 객체입니다. |
Object | 모든 자바스크립트 객체의 기본이 되는 최상위 객체입니다. |
parseFloat | 문자열 인자를 분석해서 부동소수점 숫자로 반환합니다. |
parseInt | 문자열 인자를 분석해서 특정 진수의 정수로 반환합니다. |
Promise | 비동기 작업의 최종 완료(또는 실패)와 그 결과값을 나타냅니다. |
Proxy | 객체의 기본 동작(속성 조회, 할당, 열거, 함수 호출 등)을 개발자가 원하는 대로 재정의할 수 있게 해주는 객체입니다. |
queueMicrotask | 마이크로태스크(Microtask) 큐에 콜백 함수를 대기시킵니다. |
RangeError | 어떤 값이 허용된 범위나 집합 안에 있지 않을 때 발생하는 에러입니다. |
ReferenceError | 존재하지 않는 변수를 참조하려고 할 때 발생하는 에러입니다. |
Reflect | 자바스크립트의 중간 채기(interceptable) 작업들을 위한 메서드를 제공합니다. |
RegExp | 문자들의 패턴 조합을 찾기 위해 사용하는 정규 표현식 객체입니다. |
Set | 중복되지 않는 유일한 값들의 컬렉션을 나타냅니다. |
setInterval | 일정한 시간 간격을 두고 함수를 반복해서 호출합니다. |
setTimeout | 지정된 밀리초(ms) 시간이 지난 후에 함수나 표현식을 한 번만 실행합니다. |
SharedArrayBuffer | 메모리를 공유할 수 있는 고정된 길이의 원시 바이너리 데이터 버퍼입니다. |
String | 문자들의 나열(문자열)을 나타냅니다. |
structuredClone | 어떤 값의 완벽한 깊은 복사본(Deep copy)을 만들어줍니다. |
Symbol | 객체 속성의 고유한 키 값으로 사용되는, 변경 불가능하고 유일한 데이터 타입입니다. |
SyntaxError | 문법적으로 잘못된 코드를 해석하려고 할 때 발생하는 에러입니다. |
TypeError | 어떤 값이 우리가 기대했던 데이터 타입이 아닐 때 발생하는 에러입니다. |
Uint8Array | 8비트 부호 없는 정수의 배열입니다. |
Uint8ClampedArray | 값을 0에서 255 사이로 제한(Clamp)하는 8비트 부호 없는 정수의 배열입니다. |
Uint32Array | 32비트 부호 없는 정수의 배열입니다. |
URIError | 전역 URI 처리 함수를 잘못된 방식으로 사용했을 때 발생하는 에러입니다. |
URL | 객체 URL을 생성하거나 URL 자체를 다루기 위한 정적 메서드들을 제공하는 객체입니다. |
URLPattern | URL의 특정 패턴을 나타냅니다. (라우팅할 때 많이 써요!) |
URLSearchParams | 키/값 쌍의 컬렉션(주로 쿼리 스트링)을 나타냅니다. |
WeakMap | 키가 약하게 참조(가비지 컬렉션의 대상이 됨)되는 키/값 쌍의 컬렉션입니다. |
WeakSet | 각 객체가 오직 한 번만 나타날 수 있는 객체 컬렉션입니다. |
WebAssembly | 웹어셈블리(WebAssembly) 기능에 접근할 수 있게 해줍니다. |
💡 강사의 팁:
폴리필(Polyfill)은 원래 해당 환경(여기선 엣지 런타임)에 없는 기능이지만, 마치 있는 것처럼 쓸 수 있게 프레임워크가 메꿔주는 기능이에요.AsyncLocalStorage는 원래 Node.js에만 있는 건데, Next.js가 엣지 환경에서도 쓸 수 있게 만들어 준 특별한 케이스랍니다.
next dev 로컬 개발 환경과 next build 빌드 환경 모두에서 process.env를 사용하여 환경 변수(Environment Variables)에 접근할 수 있습니다.
엣지 런타임에는 꼭 명심해야 할 몇 가지 엄격한 제한 사항이 있어요:
fs 모듈)은 할 수 없어요.node_modules 폴더 안에 있는 라이브러리들도 ES 모듈(ES Modules)을 준수하고 네이티브 Node.js API를 사용하지 않는 라이브러리에 한해서만 사용할 수 있습니다.require를 직접 호출하는 것은 허용되지 않습니다. 대신 ES 모듈 방식인 import를 사용해야 해요.또한, 아래의 자바스크립트 언어 기능들은 보안과 성능상의 이유로 비활성화되어 있어서 동작하지 않습니다:
| API | 설명 (Description) |
|---|---|
eval | 문자열로 표현된 자바스크립트 코드를 강제로 실행합니다. |
new Function(evalString) | 인자로 전달된 코드 문자열을 가지고 새로운 함수를 동적으로 생성합니다. |
WebAssembly.compile | 버퍼 소스로부터 WebAssembly 모듈을 컴파일합니다. |
WebAssembly.instantiate | 버퍼 소스로부터 WebAssembly 모듈을 컴파일하고 인스턴스화(실행 준비)합니다. |
아주 드문 경우이긴 하지만, 여러분이 작성한 코드나 혹은 npm에서 설치해 가져온 라이브러리 안에 동적 코드 평가 구문(eval 등)이 포함되어 있을 수 있어요. 만약 이 코드가 실제 런타임에는 절대 실행되지 않는 죽은 코드이고 트리쉐이킹(Tree-shaking, 불필요한 코드 제거)으로도 걸러지지 않는다면 빌드할 때 에러가 날 수 있습니다.
이럴 때는 Proxy 설정 파일에서 특정 파일들에 한해 이 엄격한 검사를 약간 느슨하게 풀어줄 수 있습니다:
export const config = {
unstable_allowDynamic: [
// 단일 파일을 허용하는 경우
'/lib/utilities.js',
// 3번째 파티 모듈인 'function-bind' 안의 모든 파일을 허용하기 위해 glob 패턴 사용
'**/node_modules/function-bind/**',
],
}
unstable_allowDynamic은 특정 파일에 대해 동적 코드 평가 검사를 무시하게 해주는 glob 패턴 문자열이나, 패턴들의 배열을 받습니다. 이 경로 패턴은 여러분의 애플리케이션 최상위 루트 폴더를 기준으로 계산됩니다.
하지만 조심하세요! 검사를 무시하도록 설정했더라도, 막상 엣지 환경에서 ওই 코드가 실제로 실행되어 버리면 여전히 런타임 에러를 던지며 앱이 죽어버립니다.
전체 문서에 대한 의미론적인 개요를 보고 싶다면 https://nextjs.org/docs/sitemap.md 문서를 참고하세요.
사용 가능한 모든 문서의 전체 색인(Index)은 https://nextjs.org/docs/llms.txt 문서를 참고하세요.
🌟 강사의 마무리 응원:
1년 넘게 꾸준히 취업 준비하시느라 정말 고생 많으셨습니다. 프론트엔드 개발자로서 공식 문서를 직접 번역하며 개념을 잡으려는 이 노력이 분명 좋은 결과로 이어질 거예요. 혹시 공부하다가 막히는 부분이 있거나 실전 포트폴리오를 만들 때 엣지 런타임 적용법이 헷갈린다면 언제든 편하게 질문해 주세요. 제가 언제나 여기서 도와드리겠습니다. 화이팅입니다!