SPACE LOGBOOK

OCEAN LOGBOOK

Node.js 의 이해…

2026.08.10

Node.js 의 이해…

2026.08.10
개발 일지 · 개념 정리

Node.js가 대체 뭔가요?
비전공자를 위한 1부터 100까지

서버 마이그레이션 중 만난 “Node20 vs Node22” 소동을 계기로, 개념부터 차근차근 정리합니다

얼마 전 새솔CRM 서버를 이전하는 작업을 하다가, “Node가 22인 줄 알았는데 20으로 나온다”는 상황을 마주했습니다. 분명 예전 서버에서 업그레이드까지 했는데, 새 서버에서는 버전이 다르게 나오니 당황스러웠죠. 이 사건을 계기로, 정작 Node가 뭔지는 한 번도 제대로 짚고 넘어간 적이 없다는 걸 깨달았습니다.

이 글은 코딩을 전공하지 않은 분들을 위해, Node.js라는 개념을 처음부터 끝까지 쉬운 비유로 풀어보는 글입니다.

1. 모든 프로그래밍 언어는 ‘엔진’이 있어야 움직인다

우리가 코드를 짠다는 건 결국 사람이 읽을 수 있는 글자를 쓰는 것뿐입니다. 컴퓨터는 이 글자만 봐서는 아무것도 못 합니다. 그래서 이 글자를 읽고 실제로 컴퓨터가 이해하는 동작으로 바꿔주는 번역기 역할의 프로그램이 반드시 필요합니다. 이걸 흔히 “엔진” 또는 “인터프리터”라고 부릅니다.

언어마다 필요한 엔진
Python 코드 → Python 엔진이 읽고 실행
Java 코드 → Java 엔진(JVM)이 읽고 실행
JavaScript 코드 → JavaScript 엔진이 읽고 실행

즉 어떤 언어든, 그 언어를 “이해하고 실행해줄 엔진”이 어딘가에 설치돼 있어야 코드가 돌아갑니다. 엔진이 없으면 그냥 텍스트 파일일 뿐입니다.

2. JavaScript의 엔진은 왜 처음부터 ‘브라우저 안에’ 박혀 있었나

여기가 핵심입니다. 1995년, JavaScript는 넷스케이프(초창기 웹브라우저 회사)에서 “웹페이지를 좀 더 살아 움직이게 만들자”는 아주 구체적인 목적 하나만으로 만들어졌습니다. 버튼 누르면 색깔 바뀌고, 입력폼에 이메일 잘못 쓰면 경고 뜨고, 이런 것들이요.

그래서 JavaScript를 실행하는 엔진 자체를 처음부터 브라우저라는 프로그램 안에 통째로 내장시켜 만들었습니다. 따로 떼서 팔거나 독립적으로 설치할 수 있는 물건이 아니라, 브라우저의 부품 중 하나로 태어난 거예요.

비유로 보면
자동차 엔진을 만들 때, 처음부터 “이 자동차 차체 안에서만 돌아가도록” 배선과 부품을 다 맞춰서 만든 겁니다. 엔진 자체는 훌륭한데, 차체 밖으로 꺼내면 시동 걸 방법이 없는 상태였던 거죠.

반면 PHP, Java, Python 같은 언어들은 처음부터 서버(그냥 컴퓨터라고 생각하시면 됩니다)에서 독립적으로 실행되도록 설계됐습니다. 브라우저 없이도 그 자체로 “저를 실행해주는 프로그램(엔진)”이 컴퓨터에 설치되면 바로 돌아갔습니다.

“브라우저 안에서만 돈다”는 게 구체적으로 뭘 의미하나
JavaScript 엔진이 브라우저 안에 있으면, JavaScript 코드가 할 수 있는 일도 딱 “브라우저가 허용해주는 일”로 제한됩니다.

할 수 있었던 것: 화면의 글자·버튼을 바꾸기, 사용자 클릭에 반응하기, 입력값 검사하기
할 수 없었던 것: 컴퓨터의 파일을 읽고 쓰기, 데이터베이스에 접속하기, 다른 컴퓨터로부터 요청을 받아 응답하기(서버 역할)

왜냐면 이런 기능들은 브라우저가 애초에 제공해주지 않았거든요. 브라우저는 “웹페이지를 보여주는 프로그램”이지 “파일 시스템을 다루는 프로그램”이 아니니까요. JavaScript 입장에서는 하고 싶어도 그런 문(API)이 아예 없었던 겁니다.

이 때문에 Node.js가 나오기 전까지는 웹사이트 하나를 만들려면 언어가 최소 두 개 필요했습니다.

프론트엔드(사용자가 보는 화면)
무조건 JavaScript (브라우저가 이해하는 언어가 이것뿐이니 선택의 여지가 없음)
백엔드(서버 쪽, 데이터베이스 연결하고 로직 처리하는 부분)
PHP나 Java, Python, Ruby 등 다른 언어

개발자도 보통 “프론트엔드 개발자”와 “백엔드 개발자”로 나뉘어서, 서로 다른 언어를 쓰며 협업하는 구조였습니다.

3. Node.js의 등장 — 엔진을 차체에서 뜯어내 새 몸체를 달아줌

2009년, 라이언 달(Ryan Dahl)이라는 개발자가 구글 크롬 브라우저 안에 있던 JavaScript 엔진(V8)을 브라우저에서 물리적으로 분리해서, 독립적으로 실행 가능한 프로그램으로 다시 포장했습니다. 그리고 여기에 브라우저가 주던 기능(화면 조작) 대신, 서버가 필요로 하는 새로운 기능들을 새로 붙여줬습니다: 파일 읽고 쓰기, 네트워크로 요청 받고 응답하기, 데이터베이스 연결하기 같은 것들이요. 이렇게 만들어진 프로그램이 Node.js입니다.

비유로 보면
그 엔진을 차체에서 뜯어내서, 완전히 새로운 몸체(서버용 차체)에 얹고, 새로운 계기판(파일 시스템 접근, 네트워크 서버 기능)을 달아준 겁니다. 엔진(JavaScript 문법 자체)은 똑같은데, 이제 브라우저라는 차체가 아니어도 시동이 걸리게 된 거죠.

그 결과 이제 JavaScript는 화면도 짜고, 서버도 짤 수 있는 언어가 됐습니다. 새솔CRM처럼 화면(프론트엔드)과 서버(백엔드) 전체를 JavaScript 하나로 만들 수 있는 게 바로 이 덕분입니다.

💡
한 문장으로 정리하면: JavaScript라는 “문법·언어” 자체는 예나 지금이나 똑같습니다. 달라진 건 그 언어를 실행해주는 “엔진을 어디에 심어놓느냐”입니다 — 브라우저 안에 심으면 화면용 JavaScript, Node.js 안에 심으면 서버용 JavaScript가 되는 겁니다.
4. Node.js ‘버전’이 있다는 것은 무슨 의미인가

Node.js는 계속 업데이트되는 소프트웨어입니다. 마치 스마트폰 운영체제(iOS, 안드로이드)가 버전이 올라가듯, Node.js도 시간이 지나며 버전이 올라갑니다. 지금 이야기하고 있는 Node 20, Node 22가 바로 그 버전 번호입니다.

1
버전이 올라가면 뭐가 좋아지나 더 빨라지거나, 보안이 강화되거나, 새로운 기능이 추가됩니다. 스마트폰 OS 업데이트와 비슷합니다.
2
왜 버전을 신경 써야 하나 어떤 부품(패키지)들은 “나는 최소 Node 22 이상에서만 작동한다”는 식으로 최소 요구 버전을 정해두기 때문입니다.
3
그럼 서버마다 버전이 다를 수 있나 네. 서버를 새로 만들면 기본적으로 그 시점에 설치되는 버전이 깔리고, 예전 서버에서 따로 업그레이드했던 이력은 자동으로 따라오지 않습니다.
5. npm과 package.json — “부품 창고”와 “부품 목록”

Node.js로 프로그램을 만들 때, 모든 기능을 처음부터 다 짜지 않습니다. 다른 사람들이 미리 만들어둔 “부품(패키지)”을 가져다 씁니다. 새솔CRM에서 PDF를 만들 때 쓰는 puppeteer, 데이터베이스로 쓰는 better-sqlite3 같은 것들이 전부 이런 부품입니다.

npm이란?
부품을 다운로드받을 수 있는 온라인 부품 상점입니다. “이 부품 주세요” 하면 컴퓨터로 내려받아줍니다.
package.json이란?
“이 프로그램은 어떤 부품들을 몇 번 버전으로 쓰고 있다”를 적어둔 부품 목록표(레시피)입니다.
node_modules 폴더란?
실제로 다운로드받은 부품들이 쌓여있는 창고입니다. 용량이 커서 보통 Git(코드 저장소)에는 올리지 않고, 서버에서 package.json을 보고 다시 내려받습니다.
6. 실전에서 겪은 일 — “부품은 새 버전, 아가미는 옛날 버전”

여기서 이번에 실제로 겪었던 일이 등장합니다. 새솔CRM에서 PDF를 만들 때 쓰는 puppeteer라는 부품을 예전 서버에서 최신 버전(25번대)으로 업그레이드했었습니다. 이 최신 puppeteer는 “나는 Node 22 이상에서만 정식으로 작동을 보장한다”고 적혀 있었습니다.

그런데 서버를 새 곳으로 이사(마이그레이션)하면서, 코드와 부품 목록(package.json)은 그대로 옮겨졌지만, 서버 자체의 Node.js 버전은 옛날 버전(20)으로 남아있었던 것입니다.

비유로 보면
최신 잠수 장비(puppeteer 25)는 챙겨서 이사를 갔는데, 정작 그 장비를 쓸 사람의 아가미(Node 버전)는 업그레이드하는 걸 깜빡한 상황입니다.
⚠️
다행히 이런 “최소 버전 요구사항(engines)”은 대부분 강제 규정이 아니라 권고 사항입니다. 그래서 실제로는 옛날 아가미(Node 20)로도 최신 장비(puppeteer 25)가 큰 문제없이 작동하는 경우가 많습니다. 실제로 이번에도 PDF 생성과 이메일 발송을 여러 차례 테스트해본 결과 정상 작동을 확인했습니다.
7. better-sqlite3와 ‘네이티브 애드온’ — 조금 더 예민한 부품

모든 부품이 puppeteer처럼 관대한 것은 아닙니다. 데이터베이스를 다루는 better-sqlite3 같은 부품은 순수 JavaScript가 아니라, 컴퓨터가 더 빠르게 이해할 수 있는 “기계어에 가까운 코드(네이티브 애드온)”로 일부가 만들어져 있습니다.

비유로 보면
puppeteer 같은 순수 JavaScript 부품은 범용 규격 나사라서 웬만한 드라이버(Node 버전)에 다 맞습니다. 반면 better-sqlite3 같은 네이티브 애드온은 그 드라이버 모델 전용으로 깎아 만든 나사에 가깝습니다. Node 버전이 바뀌면 나사(부품)를 그 버전에 맞게 다시 깎아야(재빌드) 합니다.

실제로 이번에 Node를 22로 올리는 작업을 하다가, 이 부분에서 실제 장애가 발생했습니다. Node 버전만 22로 바꾸고 better-sqlite3라는 나사는 옛날 규격(20용)으로 그대로 뒀더니, “이 나사는 이 드라이버에 안 맞습니다”라는 에러(NODE_MODULE_VERSION 불일치)가 나면서 서비스가 잠깐 멈췄습니다. 나사를 새 규격(22용)으로 다시 깎아 끼우자(재빌드) 바로 정상화됐습니다.

8. pm2와 ‘cluster 모드’ — 관리자와 일꾼들

서버에서는 프로그램을 그냥 실행만 하는 게 아니라, 죽으면 자동으로 재시작해주고 여러 개를 동시에 돌려주는 관리자 프로그램(pm2)을 씁니다.

cluster 모드란?
한 프로그램을 여러 개 복사해서 동시에 돌리는 방식입니다. 손님이 많이 몰릴 때 창구를 여러 개 여는 것과 비슷합니다.

이번에 발견된 재미있는(?) 특징은, cluster 모드로 여러 창구(워커)를 열 때는, 각 창구가 관리자(pm2 데몬) 자신의 아가미(Node 버전)를 그대로 물려받는다는 점이었습니다. 개별 창구마다 “너는 Node 22 써” 하고 따로 지정해도 소용이 없고, 관리자 자신의 Node 버전을 바꿔야 아래 창구들도 다 같이 바뀝니다. 이걸 모르고 개별 지정만 바꿨다가, 나사(better-sqlite3)와 드라이버(실제 Node 버전)가 어긋나면서 짧은 장애로 이어졌던 것입니다.

한눈에 정리
용어쉬운 설명
JavaScript원래 브라우저 안에서만 동작하던 프로그래밍 언어
Node.jsJavaScript를 브라우저 밖(서버)에서도 실행하게 해주는 프로그램
버전(20, 22 등)Node.js의 업데이트 단계 번호
npm부품(패키지)을 받을 수 있는 온라인 상점
package.json어떤 부품을 쓰는지 적어둔 목록표
node_modules실제로 받은 부품들이 쌓인 창고
네이티브 애드온Node 버전에 맞춰 다시 조립(재빌드)해야 하는 예민한 부품
pm2프로그램을 관리·재시작해주는 관리자 프로그램
cluster 모드한 프로그램을 여러 창구로 복사해서 동시에 운영하는 방식
자주 묻는 질문
Q. Node.js 버전은 무조건 최신으로 맞춰야 하나요?
A. 꼭 그렇지는 않습니다. 지금 쓰는 부품들이 문제없이 잘 돌아간다면 급하게 올릴 필요는 없습니다. 다만 부품(패키지)이 특정 버전 이상을 요구하기 시작하거나, 보안 업데이트가 필요해지면 그때 맞춰 올리는 것이 일반적입니다.
Q. 서버를 이사(마이그레이션)하면 Node 버전도 자동으로 따라가나요?
A. 아닙니다. 코드와 부품 목록(package.json)은 Git 등을 통해 옮겨지지만, 서버 자체의 Node.js 버전은 새 서버가 어떤 상태로 세팅됐는지에 따라 달라집니다. 예전 서버에서 따로 업그레이드했던 이력은 새 서버에 자동으로 반영되지 않으므로, 이사 후에는 반드시 새 서버의 Node 버전을 직접 확인해야 합니다.
Q. Node 버전을 올릴 때 가장 조심해야 할 부분은 뭔가요?
A. better-sqlite3처럼 “네이티브 애드온”이 포함된 부품입니다. 이런 부품은 Node 버전이 바뀌면 반드시 새 버전에 맞춰 다시 조립(재빌드)해줘야 하며, 여러 프로그램이 하나의 관리자(pm2)와 Node 런타임을 공유하는 구조라면 한 곳만 바꾸고 다른 곳을 놓치기 쉬우므로 전체를 함께 점검해야 합니다.

댓글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

이 기록은 여기까지지만,
생각은 아직 이동 중이다