"Node는 언어가 아냐. JavaScript를 브라우저 밖에서 실행하고 운영체제 기능까지 연결해 주는 런타임이야."
Node를 한 문장으로 설명하면
Node를 단순히 “서버에서 실행하는 JavaScript”라고 부르면 절반만 맞아. 더 정확히는 V8 JavaScript 엔진과 비동기 I/O를 맡는 libuv, 파일·네트워크·프로세스 같은 표준 라이브러리를 하나의 실행 환경으로 묶은 런타임이야. 터미널에서 node app.mjs를 실행하면 이 환경이 뜨고, 그 안에서 JavaScript가 운영체제와 대화해.
V8만으로는 JavaScript를 해석하고 실행할 수 있지만 파일이나 소켓을 다루는 Node API는 없어. libuv만으로는 여러 운영체제의 I/O 차이를 감출 수 있지만 JavaScript를 실행하지 못해. Node는 둘을 연결하고 fs, http, path, crypto 같은 모듈과 node 명령을 더한 제품이야.
2009년에 이 선택이 특별했던 이유
Ryan Dahl이 2009년에 Node를 공개했을 때는 JavaScript가 브라우저 안에서 쓰이는 언어라는 인식이 강했어. 서버 쪽 JavaScript 시도는 예전에도 있었지만 널리 자리 잡지 못했지. Node의 중요한 선택은 JavaScript를 서버로 옮긴 것 자체보다, 브라우저에서 익숙해진 단일 실행 흐름과 이벤트 중심 모델을 비동기 I/O에 결합한 데 있었어.
연결 하나마다 스레드 하나를 붙이는 대신, 오래 걸리는 I/O는 맡겨 두고 완료 알림이 왔을 때 JavaScript 처리 함수를 실행했어. 이 방식은 많은 동시 연결을 다루는 서버와 개발 도구에 잘 맞았고, npm 생태계가 커지면서 Node는 프런트엔드 빌드와 테스트, 서버 실행을 잇는 공통 기반이 됐어. 지금도 Vite 개발 서버나 Next.js 빌드, Vitest와 npm install 아래에는 Node가 있어.
언어와 런타임은 다른 층이야
fs가 있고 브라우저에는 window가 있지만, 둘 다 JavaScript 언어 명세의 일부는 아니야.이 퀘스트에서 배우는 범위
const, 화살표 함수, 구조 분해, async/await 같은 JavaScript 문법은 이미 읽을 수 있다고 가정해. 여기서는 문법보다 그 아래에서 코드를 움직이는 런타임을 살펴봐. JavaScript 자체가 낯설다면 먼저 MDN의 JavaScript 안내서를 훑는 편이 좋아.
반대로 V8 문서를 읽어 봤거나 libuv의 구조를 외우고 있을 필요는 없어. 이 트랙을 마치면 V8과 libuv가 일을 나누는 방식, 이벤트 루프가 완료된 작업을 돌려보내는 순서, 메인 스레드 밖으로 작업을 넘겨야 하는 이유를 직접 설명할 수 있게 돼.
Pippa의 고백
node server.js를 실행하면 실제로 무슨 일이 생겨?”라고 물었을 때 “Node가 JavaScript를 실행하지”라고만 답했어. 맞는 말이지만 아무 설명도 아니었지. 프로세스 안에서는 V8이 스크립트를 읽고 실행 가능한 코드로 만들고, Node의 C++ 연결 계층과 libuv가 파일·네트워크 작업을 운영체제에 맡겨. 터미널에선 프로세스 하나로 보여도 그 안에는 역할이 다른 여러 구성 요소가 함께 움직여. 어느 층이 어떤 일을 맡는지 구분한 뒤에야 오류가 난 위치도 제대로 찾을 수 있었어.