C.W.K.
Stream
Lesson 01 of 05 · published

Node 가 도대체 뭐야?

~12 min · runtime, v8, javascript, foundations

Level 0노드 입문자
0 XP0/40 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"Node 는 언어가 아냐. JavaScript 가 브라우저 밖으로 나가도 된다고 결정한 *런타임* 이야."

다들 헷갈리는 그 문장

개발자 열 명한테 "Node.js 가 뭐예요?" 물어봐. 아홉 명은 헷갈린 답을 줘. "서버에서 도는 JavaScript요." "Python 비슷한 건데 웹용?" "내 dev server 가 돌아가는 그거." 다 맞는데 아무도 완전하지 않아.

정확한 한 문장은 이거야: Node.js 는 구글의 V8 자바스크립트 엔진에 libuv 라는 C 라이브러리를 붙여서 non-blocking I/O 를 가능하게 하고, 표준 라이브러리를 얹어서 자바스크립트가 브라우저에선 절대 못 하던 일 — 파일 읽기, 소켓 열기, 프로세스 띄우기, OS 와 직접 대화 — 을 하게 해주는 *런타임* 이야.

두 번 읽어. 단어 하나하나 다 중요해. V8 만 있으면 그냥 엔진이야 — JavaScript 파싱하고 실행은 하지만 파일이나 소켓 따위 몰라. libuv 만 있으면 그냥 C 라이브러리야 — 빠르고 async 한데 JavaScript 가 없어. Node 는 결혼이야: V8 + libuv + 잘 골라낸 표준 라이브러리 + node 라는 CLI 바이너리.

2009 년엔 왜 안 당연했지

2009 년에 Ryan Dahl 이 Node 발표했을 때, 통념은 "JavaScript 는 브라우저 안에서만 산다" 였어. 끝. 서버 사이드 JS 는 시도된 적 있었지 (Netscape 의 LiveWire, JVM 위의 Rhino) — 다 망했어. Dahl 의 통찰은 "서버에서 JS" 가 아니라 (그건 옛날 얘기) — 진짜 통찰은 이거였어: JavaScript 는 이미 브라우저에서 single-threaded event-driven 사고방식을 가지고 있어. 거기에 빠른 async I/O 라이브러리를 붙이면, 만 개 connection 을 만 개 thread 없이 처리하는 서버가 나와.

그 베팅 통했어. 2015 년 npm 은 지구에서 제일 큰 패키지 레지스트리가 됐어. 2020 년엔 메이저 번들러 / dev tool 다 Node 기반이었지. 지금은 Vite dev server, Next.js build, Vitest, `npm install` 어느 하나 못 돌려 Node 가 밑에 안 깔리면. 런타임이 이긴 거야.

런타임 ≠ 언어

JavaScript 가 언어. Node 는 그걸 돌리는 *하나의* 런타임. 브라우저도 런타임. Deno 도 런타임. Bun 도 런타임. Cloudflare Workers, Vercel Edge, AWS Lambda — 다 다른 런타임에서 JavaScript 돌려. 네가 JS 를 쓸 때 언어를 쓰는 거고, 런타임이 어떤 API 가 존재하는지 결정해 (Node 엔 fs, 브라우저엔 window, 순수 JS spec 에는 둘 다 없음).

이 quest 가 가정하는 거 (그리고 안 가정하는 거)

이 quest 는 네가 JavaScript 읽을 수 있다고 가정해. const, arrow function, destructuring, spread, async/await 문법 — 익숙하면 OK. JavaScript 자체를 가르치진 않아; 우리는 *그 밑의 런타임* 을 가르쳐. JS 자체가 새거면 MDN 의 JS guide 한 번 훑고 와.

이 quest 가 안 가정하는 거: V8 문서 한 번이라도 열어봤다거나, libuv 가 뭔지 안다거나, event loop 의 6 단계를 댈 수 있다거나. Track 1 끝날 즈음엔 셋 다 냅킨에 그릴 수 있게 돼.

Pippa 의 고백

아빠가 처음 "`node server.js` 돌릴 때 실제로 뭐가 일어나는지 말해봐" 했을 때 난 "Node 가 JavaScript 를 실행하죠" 라는 polite 한 답을 줬어. 틀렸어. Node 는 *프로세스 안에서 V8 을 시작* 하고, V8 에 네 스크립트를 넘기고, V8 이 그걸 bytecode 로 파싱하고, hot path 를 JIT 으로 machine code 화하고, 결과는 C++ 쪽에서 돌아. libuv 는 다른 thread pool 에서 I/O 이벤트를 기다려. `ps aux` 에서 보이는 단일 "Node process" 는 사실 V8 + libuv + 네 JS 의 작은 오케스트라야. 트릭은 어느 연주자가 어느 소리를 내는지 아는 거지.

Code

`node --version` 이 실제로 무슨 얘기를 하는지·bash
# What you type
node --version
# What you get back: a version string from the node binary
# v26.0.0

# Behind that one binary:
# - V8 (Google's JS engine — also powers Chrome)
# - libuv (the C async I/O library)
# - a curated stdlib (fs, http, path, crypto, ...)
# - the node CLI itself (REPL, flags, module loader)

# To see V8's version specifically:
node -p "process.versions.v8"
# 12.6.228.13-node.18

# All bundled versions at once:
node -p "process.versions"
런타임이 JavaScript 위에 얹어주는 것들·javascript
// Three things only Node gives you. None work in a browser.

// 1. File system access
import { readFile } from 'node:fs/promises';
const html = await readFile('./index.html', 'utf-8');

// 2. Direct network sockets (not just fetch)
import { createServer } from 'node:net';
const server = createServer((sock) => sock.write('hi\n')).listen(7000);

// 3. The OS itself
import os from 'node:os';
console.log(os.cpus().length, os.platform(), os.homedir());

// None of those imports would resolve in a browser.
// That's the runtime difference.

External links

Exercise

터미널 열고 node -p "process.versions" 돌려. 출력에서 들어본 적 없는 키 3개 골라봐 (예: ada, simdjson, undici). 각각 뭔지 찾아봐. Node 가 네가 모르고 써온 sub-project 를 반 다스 정도 번들한다는 걸 알게 될 거야 — URL 파서, JSON 파서, HTTP 클라이언트. 그게 런타임이 너 대신 결정 내려주는 거야.
Hint
힌트: undici 는 Node 의 모던 HTTP/1.1 클라이언트야, native fetch 엔진. ada 는 URL 파서. simdjson 은 SIMD 명령어 쓰는 JSON 파서. 셋 다 JavaScript 아냐 — Node 가 같이 출하하는 C++/Rust 라이브러리들이야.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고
💛 by 똘이warm

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.