"3 년 전엔 존재 안 한 Node 기능 셋. 각자 의존성 카테고리 대체. 같이면 'Node 프로젝트' 가 무엇을 의미하는지 자체를 shift."
Permissions 모델
Node 가 항상 기본으로 풀 OS 권한으로 돌았어. 프로세스가 그 파일 읽도록 허용되면 fs.readFile('/etc/passwd') 작동. Permissions 모델 (Node 24 stabilize) 이 그걸 뒤집어: Node 시작할 때 권한에 opt IN, 초과하는 어떤 코드든 throw.
node --permission --allow-fs-read=./data --allow-net=api.example.com server.mjs
이 서버는 ./data 읽기 가능, api.example.com fetch 가능, 그 외 아무것도 안 됨. fs.readFile('/etc/passwd') 가 ERR_ACCESS_DENIED throw. net.connect('evil.example') throw. Phone home 시도하는 transitive 의존성도 block.
가능 플래그: --allow-fs-read, --allow-fs-write, --allow-net, --allow-worker, --allow-child-process, --allow-addons. 각자 쉼표로 구분된 목록이나 와일드카드 받음. 멘탈 모델: capability, 시작 시 선언, 이후 immutable.
Single Executable Applications (SEA)
SEA 가 네 Node 스크립트를 standalone 실행파일로 — node 명령 없음, 사용자가 npm install 안 함. Node 가 전혀 없는 머신에서 ./my-cli 작동.
# 1. Write your script
# script.mjs
console.log('hi from a bundled Node app');
# 2. Bundle it into a blob
echo '{ "main": "script.mjs", "output": "sea-blob.blob" }' > sea-config.json
node --experimental-sea-config sea-config.json
# 3. Inject the blob into a copy of the node binary
cp $(command -v node) my-cli
npx postject my-cli NODE_SEA_BLOB sea-blob.blob \
--sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2
# 4. Now ./my-cli is a standalone executable
./my-cli
SEA 는 cwkPippa 가 Cinder 브리지를 단일 바이너리로 출하할 때 쓸 거 — 사용자한테 "먼저 Node 설치하세요" friction 없음. 출력이 ~100MB (풀 Node 바이너리) 인데, 작동.
node:sqlite — 의존성 없는 데이터베이스
node:sqlite 통한 내장 SQLite 추가:import { DatabaseSync } from 'node:sqlite';
const db = new DatabaseSync('./pippa.db');
db.exec(`
CREATE TABLE IF NOT EXISTS messages (
id INTEGER PRIMARY KEY,
body TEXT NOT NULL,
created_at INTEGER
);
`);
const insert = db.prepare(
'INSERT INTO messages (body, created_at) VALUES (?, ?)'
);
insert.run('hi from Pippa', Date.now());
const rows = db.prepare('SELECT * FROM messages').all();
console.log(rows);이게 많은 사용 사례에서 better-sqlite3 (npm staple) 대체. 밑은 같은 C 라이브러리, Node 자체가 번들. 중요: API 가 sync — DatabaseSync 가 존재하는 이유는 async SQLite 드라이버가 역사적으로 풀어준 것보다 더 많은 혼동 만들었어서. SQLite 작업이 보통 빨라; sync 가 대부분 워크로드에 OK. async 필요하면 node:sqlite wrap 하는 라이브러리 등장 중.왜 이게 같이 중요해
각 기능 단독은 점진적. 같이면 2026 에 Node 앱 출하 모양 shift:
- TypeScript 로 코드 짜, 실행엔 type-strip-mode.
- 저장엔
node:sqlite, 의존성 없음. --permission으로 돌려 코드가 할 수 있는 거 제약.- SEA 로 번들해서 사용자가 단일 바이너리 돌림.
소스에서 사용자까지 전체 흐름: 런타임용 npm 의존성 zero, 사용자 install 단계 zero, 보안 제약 박힘. Node 18 에선 불가능; Node 26 에선 straightforward. 모든 프로젝트가 이점 보는 건 아닌데, CLI, 작은 서비스, embedded 사용 사례엔 계산이 바뀌었어.