본문으로 건너뛰기
· backend · 3분 읽기

Node.js 22에서 24로: 1분이면 되는 게 아닌 이유

Node.js 20이 2026년 4월 EOL을 맞았다. 지금 20을 쓰고 있다면 선택지가 없다. Node.js 22나 24로 가야 한다.

Node.js 24(코드명 Krypton)는 2025년 10월에 Active LTS가 됐고 2028년 4월까지 지원된다. 새 프로젝트라면 24가 답이다. 기존 22에서 올라오는 팀도 결국 같은 목적지다.

문제는 nvm use 24가 전부가 아니라는 점이다.

먼저 봐야 할 것은 런타임 변경이다

Node.js 24 업그레이드에서 먼저 확인할 것은 런타임이 바뀌면서 같이 올라오는 주변 구성이다. V8은 13.6으로 올라가고, npm은 11 계열이 기본이 된다. 여기에 오래 deprecated였던 API 제거와 글로벌 객체 추가가 같이 들어온다.

그래서 업그레이드를 node 버전 숫자만 바꾸는 작업으로 보면 놓치는 부분이 생긴다. 애플리케이션 코드, 빌드 도구, 네이티브 애드온, TLS 연결 대상을 같이 확인해야 한다.

어디서 터지나

직접 작성한 코드는 테스트에서 비교적 빨리 드러난다. 더 자주 놓치는 곳은 간접 의존성과 실행 환경이다.

  • 네이티브 애드온: V8과 Node-API 경계에 민감한 패키지는 별도 확인이 필요하다
  • 빌드 도구: npm 11, ESM/CJS 처리, 패키지 매니저 lockfile 정책이 같이 영향을 줄 수 있다
  • 레거시 코드: 오래 deprecated였던 util.is*, tls.createSecurePair() 같은 API가 남아 있을 수 있다
  • TLS 연결 대상: 내부 API, 오래된 사내 인증서, 개발용 자체 서명 인증서는 실제 Node.js 24 런타임에서 연결 테스트가 필요하다

사전 점검

업그레이드 전에 먼저 확인한다:

bash
# 제거 API 후보 확인
grep -r "util.is" src/ --include="*.js" --include="*.ts" 
  | grep -v "util.inspect|util.isDeepEqual|util.isNativeError"

# TLS 연결 대상 확인
node -e "
const https = require('https');
https.get('https://your-internal-api.com', (res) => {
  console.log('OK:', res.statusCode);
}).on('error', (e) => console.error('FAILED:', e.message));
"

연결되는 모든 엔드포인트에 돌려봐야 한다. 자체 서버뿐 아니라 호출하는 외부 API도 포함한다. 인증서 키 길이나 암호 스위트가 의심된다면 openssl s_clientopenssl x509 -text로 별도 확인한다.

TLS 임시 우회는 진단으로만 둔다

레거시 TLS 문제를 확인하기 위해 보안 레벨이나 cipher 설정을 낮추는 코드를 볼 때가 있다. 이런 코드는 원인 분리용 진단에만 둬야 한다.

javascript
const https = require('https');

const agent = new https.Agent({
  ciphers: 'DEFAULT@SECLEVEL=1'
});

// 이 agent로 연결하면 보안 레벨 1로 다운그레이드
https.get('https://legacy-endpoint.com', { agent }, (res) => {
  console.log(res.statusCode);
});

근본 해결은 인증서 재발급, 서버 TLS 설정 수정, 레거시 엔드포인트 교체다. 런타임 업그레이드를 핑계로 보안 설정을 낮춰 고정하면 이후 장애와 보안 리스크가 같이 남는다.

V8 13.6: 라이브러리 덜어내기

V8이 13.6으로 올라가면서 직접 쓸 수 있는 게 늘었다.

Iterator Helpers

lodash나 iterare 없이 이터레이터 조작이 된다:

javascript
// 이전: lodash 또는 커스텀 코드
const result = _.chain([1, 2, 3, 4, 5])
  .filter(n => n % 2 === 0)
  .map(n => n * 10)
  .value();

// Node.js 24: 네이티브 Iterator Helpers
const result = [1, 2, 3, 4, 5]
  .values()
  .filter(n => n % 2 === 0)
  .map(n => n * 10)
  .toArray();
// → [20, 40]

배열뿐 아니라 Set, Map, 제너레이터 함수 등 모든 이터러블에 된다.

URLPattern 안정화

path-to-regexp를 대체할 웹 표준 API가 안정화됐다:

javascript
// 이전: path-to-regexp
const { pathToRegexp } = require('path-to-regexp');
const re = pathToRegexp('/user/:id');

// Node.js 24: URLPattern (import 불필요)
const pattern = new URLPattern({ pathname: '/user/:id' });
pattern.test('https://example.com/user/42'); // true

const match = pattern.exec('https://example.com/user/42');
match.pathname.groups.id; // '42'

라우팅에서 외부 라이브러리 의존성을 하나 줄일 수 있다.

추가된 글로벌

Float16Array, CloseEvent 등이 글로벌에 추가됐다. 이걸 폴리필하고 있었다면 제거해야 한다. 중복 정의로 예상치 못한 동작이 나올 수 있다.

제거된 API

util.is*() 메서드

Node.js 4부터 deprecated였던 메서드들이 최종 제거됐다:

javascript
// 제거됨 → 대체
util.isArray(val)           // Array.isArray(val)
util.isBoolean(val)         // typeof val === 'boolean'
util.isBuffer(val)          // Buffer.isBuffer(val)
util.isDate(val)            // val instanceof Date
util.isError(val)           // val instanceof Error
util.isFunction(val)        // typeof val === 'function'
util.isNull(val)            // val === null
util.isNullOrUndefined(val) // val == null
util.isNumber(val)          // typeof val === 'number'
util.isString(val)          // typeof val === 'string'
util.isUndefined(val)       // val === undefined

코드베이스 검색:

bash
grep -r "util.is" src/ --include="*.js" --include="*.ts" 
  | grep -v "util.inspect|util.isDeepEqual|util.isNativeError"

tls.createSecurePair()

Node.js 0.11부터 deprecated. tls.TLSSocket으로 교체한다:

javascript
// 제거됨
const pair = tls.createSecurePair(context, isServer);

// 대체
const tlsSocket = new tls.TLSSocket(socket, {
  secureContext: context,
  isServer
});

fs.truncate(fd, ...)

파일 디스크립터를 받는 시그니처가 제거됐다:

javascript
// 제거됨
fs.truncate(fd, len, callback);

// 대체
fs.ftruncate(fd, len, callback);

마이그레이션 체크리스트

순서가 있다. 런타임 호환성 먼저, API 제거와 의존성 점검을 그 다음에 본다.

1단계: 런타임 호환성 확인

  • Node.js 24로 테스트 전체 실행
  • 네이티브 애드온 사용 패키지 확인
  • npm 11에서 install/build가 재현되는지 확인
  • 연결하는 모든 외부/내부 API 엔드포인트 TLS 테스트

2단계: 제거된 API 확인

  • util.is*() 사용처 grep 후 교체
  • tls.createSecurePair() 사용처 확인
  • fs.truncate(fd, ...) 사용처 ftruncate로 교체
  • url.parse() 런타임 deprecation 경고 확인 (아직 제거 전이지만 대비)

3단계: CI 매트릭스 추가

yaml
# .github/workflows/test.yml
strategy:
  matrix:
    node: [22, 24]

4단계: 의존성 점검

bash
npm outdated
# 네이티브 애드온 있으면 V8 13.6 호환성 별도 확인

5단계: .nvmrc 업데이트

bash
echo "24" > .nvmrc

Node.js 20에서 올라오는 경우

22를 거치지 않고 바로 24로 가도 된다. 단, 20→22→24 순으로 변경사항을 추적하는 게 디버깅할 때 편하다. Node.js 22에서 이미 deprecated 경고가 뜬 API들이 24에서 제거됐기 때문에, 22로 먼저 올려서 경고를 잡으면 24 이전이 깨끗해진다.


참고 자료

공유하기 X LinkedIn

관련 글