프롤로그 — Ryan Dahl의 두 번째 자기 부정
Ryan Dahl은 2009년 Node를 만들었고, 2018년 JSConf EU에서 "Node에서 후회하는 10가지"라는 유명한 발표를 했다. 그리고 Deno를 만들었다. 보안은 기본 deny, TS는 일급, 의존성은 URL import, `package.json`은 없다 — 모든 것이 Node에 대한 명시적인 답이었다.
그런데 2024년 9월, **Deno 2**가 나왔다. 가장 큰 변화는 **자기 부정**이다.
- `package.json` 지원 — 1급 시민으로.
- `node_modules` 디렉토리 지원 — 옵션이지만 활성화 가능.
- npm 레지스트리에서 패키지 import — `npm:`/`jsr:` specifier로.
- `deno install`을 npm 호환 패키지 매니저로.
- workspace(모노레포) 지원.
> Deno가 처음에 거부했던 거의 모든 Node의 디자인 결정을, 6년이 지나서 받아들였다. 자존심을 죽이고.
이건 후퇴인가, 진화인가. 둘 다다. **이상주의에서 실용주의로**의 전환이고, 동시에 **JS 생태계의 현실**(npm은 사라지지 않는다)을 인정한 베팅이다.
이 글은 Deno 2 출시 후 약 20개월이 지난 2026년 5월 시점에서, Deno의 베팅이 어디까지 왔는지, Bun과 Node 22+와의 삼파전이 어떻게 정리됐는지, 그리고 보안 모델·JSR·Fresh 2·Deno KV가 현실에서 어떤 자리를 차지했는지를 정리한다.
1장 · Deno 2의 핵심 — Node 호환이 기본이 되다
Deno 1의 세계관, 그리고 그 한계
Deno 1은 **순수한 세계**를 그리려 했다.
- URL import — `import { foo } from "https://deno.land/std/...";`
- 명시적 권한 — `deno run --allow-net=api.example.com server.ts`
- TypeScript 일급 — 설정 없이 `.ts` 실행.
- `node_modules` 없음, `package.json` 없음.
문제는 단순했다. **JS 세계의 90%가 이미 npm 위에 있었다.** Express, React, Prisma, AWS SDK, Sentry, Stripe SDK — 다 npm. Deno는 처음에 호환 레이어로 `npm:` specifier를 추가했지만, 진짜 production에 가져가려면 부족했다. `package.json`에 적힌 의존성을 그대로 못 읽고, `node_modules` 풀스택 도구가 다 깨지고, monorepo 워크플로우가 어색했다.
Deno 2의 답은 명확했다. **"Node가 했던 방식 그대로도 돈다."**
무엇이 바뀌었나 (2024년 9월)
Deno 2 — 기존 Node 프로젝트에서
deno install # package.json 읽어서 node_modules 생성
deno run npm:express # npm 패키지 직접 실행
deno task dev # package.json의 scripts.dev 실행
| 영역 | Deno 1 | Deno 2 |
| --- | --- | --- |
| `package.json` | 무시 / 부분 지원 | 1급 — `deno install`이 읽음 |
| `node_modules` | 의도적으로 없음 | 옵션 — `nodeModulesDir: auto` |
| npm 패키지 | `npm:` specifier | 동일 + `package.json`에서 자동 |
| `deno install` | URL 기반 binary install | Node 호환 패키지 매니저 |
| `deno run npm:foo` | 부분 지원 | 안정적, 광범위 호환 |
| workspace | 없음 | 1급 — `deno.json`의 `workspace` 필드 |
> Deno 2의 모토는 더 이상 "Node를 대체한다"가 아니다. **"Node와 Deno 사이의 마찰을 0에 가깝게 만든다"**다.
마이그레이션이 쉬워졌나
실제로 기존 Node 프로젝트를 가져다 Deno로 도는지 시도해봤다.
- 작은 Express API — 5분 안에 도는 경우 많음. `deno run --allow-net --allow-read npm:tsx server.ts`.
- Next.js — 동작. 다만 `next dev`/`next build`는 Node를 직접 부르는 일이 많아 권한 모델의 의미가 흐려짐.
- Prisma + Postgres — 동작. native binary 호환에 약간의 마찰이 있을 수 있음.
- AWS SDK v3 — 거의 그대로 동작.
처음 1년 마찰이 큰 영역은 **native addon**(sharp, canvas, bcrypt-native 같은 C++ 바인딩)이었고, 2025년 동안 N-API 호환이 점진적으로 좋아졌다. 2026년 mid 시점에서 일반 npm 패키지의 90% 이상은 별 문제 없이 Deno 2에서 돈다.
2장 · `deno install` — npm 호환 패키지 매니저
두 모드
`deno install`은 두 가지 모드로 동작한다.
글로벌 binary 설치 (Deno 1부터)
deno install -gA --name lint jsr:@std/cli/parser
프로젝트 의존성 설치 (Deno 2 신규)
deno install # package.json 읽기, node_modules 생성
deno install --add npm:express@4 # 새 의존성 추가
deno install --add jsr:@hono/hono # JSR 의존성 추가
두 번째 모드가 패러다임 전환이다. `npm install`, `pnpm install`, `yarn install`을 그대로 대체할 수 있는 명령이 된 것이다.
속도와 lockfile
hot cache, 500개 deps:
npm install: 14s
pnpm install: 4s
bun install: 1.3s
deno install: 2.1s
`bun install`만큼은 아니지만, `pnpm install`보다 빠르고, `npm install`보다는 한참 빠르다. lockfile은 `deno.lock` (텍스트 JSON)이고, 처음부터 diff-friendly로 설계됐다. Bun이 binary lockfile로 한 번 헛발 디딘 것과 대조적이다.
node_modules 모드
// deno.json
{
"nodeModulesDir": "auto", // 또는 "manual" 또는 false
"lock": true
}
`auto`로 두면 `package.json`을 읽고 자동으로 `node_modules`를 만든다. `manual`은 npm/pnpm/yarn으로 깔린 기존 `node_modules`를 그대로 쓴다 (큰 monorepo 이전 시나리오). `false`이면 Deno 1 스타일의 글로벌 캐시만 사용.
> 이 옵션이 있다는 것 자체가 **이상주의를 버리고 실용주의를 택한 증거**다.
3장 · `deno run`으로 npm 패키지 직접 실행
`npm:` specifier의 진화
Deno 2의 모토 중 하나는 **"npm 패키지를 추가 설정 없이 import한다"**이다.
// app.ts
const app = express();
app.get("/", (_, res) => res.json({ ok: true }));
app.listen(3000);
deno run --allow-net --allow-read --allow-env app.ts
이게 그냥 돈다. `package.json`도 필요 없고, `node_modules`도 필요 없다 (글로벌 캐시에 가져옴). Bun과 Node가 `package.json`을 필수로 요구하는 것과 비교해, **단일 파일 스크립트**에서 Deno가 가장 매끄럽다.
Bun과 Node와의 비교
단일 파일 npm 의존성 스크립트
Deno
deno run --allow-net script.ts
Bun
bun script.ts # bun add 했어야 함, 또는 inline shebang trick
Node
npm init -y && npm i express && node script.js
> **Quick script + npm 한두 개**의 영역에서는 Deno가 dev 경험 우세. 이건 Deno 1부터 이어진 강점이 Deno 2에서도 살아남은 영역이다.
4장 · JSR — JavaScript Registry의 베팅
왜 또 다른 레지스트리
JSR(jsr.io)은 Deno 팀이 2024년 초 출시한 **새 JavaScript 레지스트리**다. npm이 이미 있는데 왜 또?
JSR의 베팅 명제는 이렇다.
1. **TS-native publishing** — TS 소스를 그대로 publish. 받는 쪽이 빌드 도구를 골라 쓴다. (npm은 보통 컴파일된 JS+.d.ts 묶음.)
2. **표준 ESM only** — CJS 없음, `package.json`의 미로 없음.
3. **runtime-agnostic** — Deno뿐 아니라 Node, Bun, browser에서 import 가능.
4. **품질 점수** — `score`로 문서·테스트·타입의 완성도 표시.
5. **scope 1급 시민** — `@scope/package` 모델이 기본.
사용 예
// 그냥 import
package.json 스타일
deno install --add jsr:@hono/hono
Node에서도 사용 가능
npx jsr add @hono/hono
또는 직접 — 빌드된 형태로 받음
채택 현실 — 2026 mid
| 카테고리 | JSR 채택 |
| --- | --- |
| Deno 1st-party `@std` 라이브러리 | 100% — `@std`의 새 home |
| Deno 생태계 도구 | 광범위 — Hono, Fresh, Oak 등 |
| 일반 JS 라이브러리 | 천천히 — npm도 같이 publish하는 경우 多 |
| 사용자 수 | npm의 작은 일부 — 단 빠르게 성장 |
> JSR은 **"npm을 죽인다"**가 아니라 **"TS-first의 다른 옵션을 만든다"**이다. 그리고 일정 부분 성공했다 — Deno 생태계 안에서는 standard, 그 밖에서는 niche.
JSR이 가져온 변화
- TS 라이브러리 저자가 **빌드 도구 선택을 사용자에게 미룰 수 있게** 됨. 그것만으로도 큰 단순화.
- npm의 `"exports"` 미로(CJS/ESM/types 경로 매핑)를 우회할 수 있는 길이 생김.
- semver/타입/문서가 통합된 score 시스템 — package 품질에 대한 첫 진지한 표준화 시도.
npm 쪽의 반응
흥미로운 디테일 하나. Deno는 2024년 npm CLI의 **BSD 라이선스 fork**를 만들었다 — 이름은 `npm`이 아니라 `pkg` 비슷한 다른 이름으로 (커뮤니티 가이드라인 준수 차원). 이게 작은 라이선스/네이밍 논쟁을 일으켰지만, npm Inc. 쪽에서 큰 법적 대응은 없었다. 결국 메시지는 **"npm 호환이 우선이지, 적대가 우선이 아니다"**.
5장 · Fresh 2 — 아일랜드 아키텍처의 두 번째 라운드
Fresh 1의 약속
Fresh는 Deno의 공식 풀스택 프레임워크였다. 핵심 컨셉:
- **No build step** — dev에서 곧바로 도는 SSR.
- **Islands architecture** — 페이지의 일부만 hydrate(클라이언트 JS), 나머지는 정적 HTML.
- **JSX with Preact** — React가 아닌 Preact, 가벼움 우선.
- **Deno-native** — 라우팅·핸들러를 Deno의 `Request`/`Response` 표준으로.
훌륭한 베팅이었지만, 1.x 시기에는 **routing 모델의 한계** (file-based + handler 분리)와 **React 생태계 호환의 부재**가 도입을 제한했다.
Fresh 2가 바꾼 것
// routes/api/hello.ts (Fresh 2 스타일)
export const handler = define.handlers({
async GET(ctx) {
return new Response(JSON.stringify({ msg: "hello" }), {
headers: { "content-type": "application/json" },
});
},
});
// routes/index.tsx
export default define.page<{ now: string }>((props) => (
));
Fresh 2의 주요 변경:
- **타입 추론 개선** — `define`을 통해 핸들러/페이지의 데이터 타입이 자동 전파.
- **server components 비슷한 패턴** — async 컴포넌트, 페이지 단위 데이터 fetch.
- **better island detection** — `islands/` 디렉토리의 컴포넌트만 hydrate.
- **Tailwind 통합 개선** — 빌드 step 없이 dev에서 Tailwind 사용.
- **`deno deploy` 통합** — `deno deploy`로 한 줄 배포.
Fresh가 채택을 못 따라잡은 이유 (솔직히)
- **Next.js의 무게**가 너무 크다. 풀스택을 시작한다면 90%는 Next.js로 간다.
- **Preact** 선택이 React 생태계의 일부 라이브러리(특히 일부 Form/Data/Animation lib)와의 호환에서 마찰을 만든다.
- **Deno 외 런타임 미지원** — Vercel/Cloudflare처럼 다른 런타임에서 돌리고 싶을 때 어색.
> Fresh 2는 **Deno Deploy에 묶인 풀스택**이라면 매우 좋은 선택. 그러나 풀스택의 default가 될 길은 좁다.
6장 · Deno KV — 내장 KV가 production-ready로
Deno KV의 정체
Deno KV는 **Deno 런타임 안에 내장된 key-value 스토어**다. SQLite와 비슷한 단일 노드 모드, 그리고 Deno Deploy 환경에서는 **글로벌 분산** 모드.
// kv.ts
const kv = await Deno.openKv();
// set
await kv.set(["users", "alice"], { name: "Alice", joined: Date.now() });
// get
const result = await kv.get<{ name: string }>(["users", "alice"]);
console.log(result.value?.name); // "Alice"
// list (prefix query)
for await (const entry of kv.list({ prefix: ["users"] })) {
console.log(entry.key, entry.value);
}
// atomic transaction
await kv.atomic()
.check({ key: ["counter"], versionstamp: null })
.set(["counter"], 1)
.commit();
2026 시점의 상태
| 측면 | 상태 |
| --- | --- |
| Local (SQLite-backed) | GA (production-ready) |
| Deno Deploy (FoundationDB-backed, global) | GA |
| Cross-region replication | 자동 |
| Atomic transactions | 지원 |
| Queue API | 지원 (`kv.enqueue`) |
| Watch API | 지원 — 실시간 구독 |
| Limit | per-key 64KB value, 일부 결제 플랜 제한 |
> Deno KV는 Cloudflare KV와 Workers KV의 자리를 노린 것이지만, Deno 생태계 안에 묶여 있는 만큼 **포지셔닝이 더 빡빡하다.** 그러나 "1줄로 시작 가능한 분산 KV"라는 슬로건은 진짜 작동한다.
어디서 잘 쓰이나
- 세션 스토어 — JWT 대신 server-side 세션.
- 피처 플래그 — 글로벌 분산이 의미 있는 작은 read-heavy 데이터.
- queue / 작업 분배 — `kv.enqueue` + worker.
- 캐시 — 짧은 TTL의 응답 캐시.
어디가 약한가
- 본격 RDB 자리에는 안 맞음 — schema, join, 트랜잭션 범위가 좁음.
- 외부 서비스에서 KV로 직접 접근하기 어려움 (반드시 Deno 런타임을 통과).
- 대용량 value는 다른 곳에 두고 KV는 메타데이터만.
7장 · workspace — Deno의 monorepo 답
모노레포가 1급 시민이 된다
Deno 2에서 `deno.json`의 `workspace` 필드가 추가됐다.
// 루트 deno.json
{
"workspace": [
"./packages/api",
"./packages/web",
"./packages/shared"
],
"tasks": {
"dev": "deno task --filter=* dev"
}
}
// packages/api/deno.json
{
"name": "@app/api",
"version": "0.1.0",
"exports": "./mod.ts",
"tasks": {
"dev": "deno run --watch --allow-net mod.ts"
}
}
내부 패키지를 `import { foo } from "@app/shared"`로 import 가능. pnpm workspace나 Bun workspace와 거의 같은 모델인데, Deno의 lockfile/캐시 일원화 덕에 설치 시간이 매우 짧다.
Turborepo·Nx와의 비교
| 도구 | 장점 | 단점 |
| --- | --- | --- |
| Deno workspace | 무설정, lockfile 통합, 빠른 install | task orchestration이 단순 |
| pnpm workspace | 광범위 호환, 모두 익숙 | install이 Deno보다 느림 |
| Turborepo | 빌드 캐싱, 강력한 그래프 | 설정 무게 |
| Nx | 강력한 generator, 큰 모노레포 표준 | 학습 곡선 큼 |
> Deno workspace는 **작은~중간 모노레포**에서 매끄럽다. 빌드 그래프 캐싱이 필수가 되는 큰 모노레포는 Turborepo/Nx를 그대로 쓰는 게 안전.
8장 · 보안 모델 — 여전히 킬러 피처
Deno의 처음부터 끝까지 살아남은 차별점이 이거다. **기본 deny**.
permission flag 한눈에
deno run script.ts # 거의 아무것도 못 함
deno run --allow-read script.ts # 파일 읽기
deno run --allow-net script.ts # 네트워크
deno run --allow-env script.ts # 환경변수
deno run --allow-write=./data script.ts # 특정 디렉토리만 쓰기
Deno 2부터: 더 세밀한 지정
deno run --allow-net=api.example.com,db.internal:5432 script.ts
deno run --allow-env=DATABASE_URL,REDIS_URL script.ts
운영에서의 실제 의미
**좋은 점:**
- 의존성에 악성 코드가 섞여 들어와도 폭주를 막을 수 있음 (supply chain attack 방어).
- production 컨테이너의 권한을 OS 외에 **런타임 레이어**에서 한 번 더 좁힘.
- AI 에이전트의 sandbox 런타임으로 매우 좋음 — 모델이 시킨 코드가 무엇을 할 수 있는지 명시적.
**마찰:**
- 첫 1주는 매번 "어떤 권한이 필요한지" 추측해야 함.
- `--allow-all` 또는 `-A`로 끄고 시작하는 사람이 많음. 그러면 효과가 0.
- 개발 환경과 production 환경에서 다른 권한을 줘야 하는 경우 설정이 복잡.
Deno 2의 보안 개선
- `--allow-net` 등에 **CIDR/도메인 단위 지정** 더 정교화.
- `--deny-net` 등 **명시적 거부** 플래그 추가 — allow 전체에서 일부만 제외.
- production 모드 권장 — `deno deploy` 환경에서 자동 narrow permission.
- audit/trace — 어떤 권한이 실제로 호출됐는지 로깅.
> 보안 모델은 **소프트웨어 공급망 공격이 늘어나는 2025~2026 시기에 가치가 커진** 영역이다. xz utils 사건, npm `event-stream` 사건 이후, "기본 deny"의 가치를 진지하게 보는 회사가 늘었다.
9장 · Deno 3는 어디에 있나
2026 mid 시점의 상태
Deno 3는 **아직 공식 출시 전**이다 (2026년 5월 기준). 로드맵 글과 RFC 토론에서 다음 방향이 보인다.
- **WinterCG 1.0 적합성** 강화 — fetch, Streams, Response의 표준 일치.
- **TypeScript의 type-check 옵션의 default 재고** — Deno 2까지는 type check가 기본이었으나, 무거움 때문에 default off에 대한 논의가 있음.
- **Node API 호환의 마지막 빈틈** — `cluster`, `dgram`, 일부 `inspector` 영역.
- **JSR과의 더 깊은 통합** — score, security advisory 같은 메타데이터를 CLI에서 활용.
- **Deno Deploy의 isolate-per-region 모델 진화** — Cloudflare Workers와의 직접 경쟁.
진짜 큰 베팅이 나올지, 아니면 점진적인 업그레이드로 갈지는 아직 정해지지 않았다. **Deno 2가 큰 자기 부정이었던 만큼**, Deno 3는 보수적인 evolution일 가능성이 더 크다.
10장 · Deno vs Bun vs Node 22+ — 삼파전의 정리
2026 mid 시점의 자리
| 축 | Node 22+ | Bun | Deno 2 |
| --- | --- | --- | --- |
| 채택률 | 1위 (압도적) | 2위 (개발 도구 중심) | 3위 (특정 영역) |
| 시작 시간 | 35~60ms | 10~20ms | 25~40ms |
| Node 호환 | 100% (본인) | 90~95% | 90~95% (Deno 2 이후) |
| TS native | `--experimental-strip-types` | 무설정 | 무설정 |
| 보안 모델 | 표준 (모두 허용) | 표준 | 기본 deny |
| 표준 라이브러리 | 큰 코어 | 작음 | `@std` 풍부 |
| 패키지 매니저 | npm/pnpm/yarn | `bun install` | `deno install` |
| 레지스트리 | npm only | npm only | npm + JSR |
| 풀스택 프레임워크 | Next/Astro/Remix | (그대로 Node 위의 것) | Fresh 2 |
| 내장 KV | 없음 | bun:sqlite | Deno KV |
| Edge 배포 | Vercel/Netlify | Cloudflare Workers는 별도 isolate | Deno Deploy |
| AI 에이전트 sandbox | 가능 (수동) | 가능 | 매우 적합 (권한 모델) |
의사결정 가이드
**Deno 2가 맞는 곳:**
1. **AI 에이전트 sandbox** — 모델이 생성한 코드를 권한 제한해 실행. 이 영역에서 Deno는 분명한 1위.
2. **고보안 / 정부 / 금융의 일부 워크로드** — permission 모델이 audit 추적에 의미 있음.
3. **새 프로젝트의 빠른 prototype** — 단일 파일 스크립트 + npm 의존성을 가장 매끄럽게.
4. **Deno Deploy 위의 작은 풀스택** — Fresh 2 + Deno KV.
5. **`@std` 중심의 backend 도구** — 표준 라이브러리의 안정성이 매력적.
**Bun이 맞는 곳:**
1. CI 속도 (`bun install`, `bun test`).
2. CLI 도구 (`bun build --compile`).
3. Edge cold start.
4. SQLite-heavy 작은 서비스.
**Node 22+가 여전히 맞는 곳:**
1. 대부분의 enterprise production.
2. APM/observability가 중요한 환경.
3. 큰 monorepo with native addons.
4. 회사 표준 런타임 — 사람을 뽑기 쉬움.
> 세 런타임은 **zero-sum이 아니다.** 한 회사 안에서 Node (메인 서비스), Bun (CLI/CI), Deno (AI 에이전트 sandbox, 고보안 부분)을 섞는 패턴이 점점 흔하다.
11장 · npm 호환의 broken / over-delivered 영역
Over-delivered
- **`deno install`의 안정성** — Deno 1 사용자들이 의심하던 것보다 매끄럽게 들어옴.
- **`npm:` specifier 호환** — Express, Hono, Zod, Prisma client, AWS SDK 등 메이저 라이브러리 거의 다 OK.
- **`deno deploy`의 npm 패키지 지원** — Cloudflare Workers가 v8 isolate 제약으로 못 도는 일부 npm을 Deno Deploy는 돈다.
- **Deno KV의 GA** — 초기 베타 시기 우려를 깨고 production-ready.
- **JSR의 score 시스템** — package 품질에 대한 첫 진지한 표준화 시도, 빠르게 자리 잡음.
Broken / 아직 약한
- **native addon (N-API)** — sharp, canvas, bcrypt 같은 일부 모듈은 여전히 마찰. 점점 좋아지고 있지만 0이 아님.
- **APM auto-instrumentation** — Datadog/NR의 Node-level instrumentation을 Deno에서 똑같이 받지 못함. 이건 Bun과 똑같이 약한 영역.
- **debugger 통합** — Chrome DevTools 프로토콜 호환은 있지만, VSCode 디버거 통합의 안정성은 Node보다 한 발 뒤.
- **Fresh 채택률** — Next.js의 무게를 못 깬다. Fresh 2가 좋아져도.
- **JSR 채택률** — Deno 생태계 밖으로 확장이 느림.
- **Deno 3 일정의 불투명** — 큰 다음 마일스톤이 아직 흐림.
12장 · 누가 production에서 Deno 2를 쓰나
케이스 A — AI 에이전트 sandbox
가장 분명한 win 영역. 모델이 생성한 코드를 실행할 때 권한을 좁히는 것이 중요한 환경:
- e2b, Modal, Replit 같은 AI 인프라의 일부 옵션.
- 자체 코드 인터프리터를 만드는 스타트업의 backend.
- Claude / GPT의 tool use에서 코드 실행 도구를 self-host하는 경우.
케이스 B — Deno Deploy 풀스택
Fresh 2 + Deno KV로 만든 작은 풀스택:
- 사내 dashboard, 마이크로 SaaS.
- API + 정적 페이지의 결합형 서비스.
- 글로벌 read 분산이 필요한 작은 데이터.
케이스 C — 표준 라이브러리 헤비한 backend 도구
`@std/cli`, `@std/path`, `@std/fs`, `@std/encoding`을 적극 쓰는 CLI 도구나 dev tool. 외부 의존성 최소화가 가치 있는 곳.
케이스 D — Slack/Discord bot, webhook handler
`Deno.serve` + `Deno.openKv()`로 작은 webhook 서비스. 권한 모델로 안전하게 좁힘, 글로벌 배포는 Deno Deploy로.
케이스 E — 거의 없음 — 대규모 enterprise 모놀리스
Bun과 같은 이유. APM, debugger, 사람의 익숙함, 기존 코드베이스의 무게.
명시적 사례 (공개 글 기준)
- **Netlify Edge Functions** — Deno 기반 런타임.
- **Supabase Edge Functions** — Deno 기반.
- **Slack/Salesforce의 일부 자동화** — Deno 권한 모델 활용.
- **Deno Deploy 자체** — eat your own dogfood.
13장 · 마이그레이션 — Node 프로젝트를 Deno 2로 옮기는 단계
단계적 도입
1. **`deno fmt`, `deno lint`만 도입** — 다른 도구 변경 없음. 무리 없는 첫 step.
2. **CI에서 `deno test`** — Vitest/Jest와 병행. Deno test의 속도와 무설정 매력 확인.
3. **단일 script를 Deno로** — `scripts/migrate.ts` 같은 일회성 스크립트부터.
4. **새 작은 서비스를 Deno로** — 신규 마이크로서비스 / 내부 도구.
5. **`deno install`로 dep 관리** — Node 런타임 유지하면서 Deno의 install만 사용.
6. **production 런타임을 Deno로** — 가장 큰 step, 마지막.
도입 체크리스트
- [ ] 우리 APM (Datadog/NR/Sentry)이 Deno를 지원하나? instrumentation 수준은?
- [ ] native addon 의존성 (sharp, canvas, bcrypt)이 Deno에서 도나?
- [ ] 우리 CI 이미지가 Deno를 받을 수 있나? `denoland/deno` 공식 이미지 활용.
- [ ] 권한 모델을 production에서 진짜로 좁힐 의지가 있나? `-A`로 끄면 차별점이 사라짐.
- [ ] Fresh 2 같은 Deno 1st-party 도구를 쓸 건가, 아니면 Hono/Express의 Deno 모드로 갈 건가?
- [ ] rollback 시나리오 — Deno→Node로 돌아가는 비용은?
흔한 anti-pattern
- **`-A`로 모든 권한을 켜고 시작하고 그대로 두기.** 권한 모델의 가치를 0으로 만듦.
- **Fresh를 풀스택 default로 강제.** Next.js 생태계의 풍요를 포기하는 결정, 정말 이유가 있어야 함.
- **JSR-only로 publish.** 사용자 기반의 80%가 npm 사용자. 둘 다 publish하는 게 안전.
- **Deno KV를 RDB 자리에 두기.** 작은 read-heavy 영역에 맞고, 트랜잭션·조인이 복잡한 곳에는 부적합.
- **`deno run`을 `node` drop-in으로 가정.** 호환은 좋아졌지만 100%가 아님. 핵심 경로는 측정하자.
- **벤치마크 차트만 보고 결정.** 본인 워크로드에서 측정 필수.
에필로그 — 이상주의에서 실용주의로
Deno 1은 **Node에 대한 명시적 반박**으로 태어났다. Deno 2는 **그 반박을 절반 거두고 실용주의를 택**했다. 그 결과:
> **Deno는 "Node를 대체한다"는 narrative를 포기했고, 대신 "Node의 옆에서 의미 있는 자리를 만든다"는 narrative로 갔다.** 그 자리가 AI 에이전트 sandbox, Deno Deploy, 표준 라이브러리 중심 도구다.
기억할 점:
- **Deno 2는 Node 코드의 마이그레이션을 어렵지 않게 만들었다.** 90%는 그냥 돈다. 마찰은 native addon, APM, 일부 debugger.
- **JSR은 npm을 죽이지 못했지만, Deno 생태계의 default가 됐다.** TS-native publish는 진짜 깔끔한 장점.
- **Fresh 2는 좋아졌지만 Next.js의 자리는 못 빼앗는다.** Deno Deploy 묶음에서는 매력적.
- **Deno KV는 production-ready다.** 작은 서비스의 1줄 KV로 충분히 가치 있음.
- **보안 모델은 AI 시대에 가치가 커졌다.** 모델이 생성한 코드 실행은 Deno의 자연스러운 home.
- **Deno 3는 아직 공식 발표 전.** 큰 자기 부정 두 번은 어렵다, 점진적 evolution이 예상.
채택 체크리스트 (Deno를 도입하기 전)
- [ ] 진짜 권한 모델이 필요한 워크로드인가, 아니면 `-A`로 끌 건가?
- [ ] APM/observability 요구 수준이 어떤가? Datadog/NR 풀스택 instrumentation이 필수면 아직 Node 권장.
- [ ] native addon 의존성을 다 확인했나?
- [ ] CI 이미지·Dockerfile에 Deno를 추가할 준비가 됐나?
- [ ] 새 작은 서비스부터 시작할 건가, 아니면 기존 코드 마이그레이션부터 할 건가? 전자가 거의 항상 옳음.
- [ ] Deno Deploy를 쓸 건가, 아니면 자체 인프라(쿠버네티스/Fly)에 Deno 컨테이너를 둘 건가?
흔한 anti-pattern (재강조)
- 권한 모델을 켜놓고 모든 권한을 허용해 가치를 0으로 만들기.
- Fresh를 신규 프로젝트 default로 강요.
- Deno KV를 RDB 자리에 두기.
- JSR-only publish로 사용자 기반의 80%를 포기.
- `npm:` import의 호환을 100%로 가정하기.
- 본인 워크로드 측정 없이 벤치마크 차트를 인용.
다음 글 예고
- **"AI 에이전트 sandbox 런타임 비교 2026 — Deno, Bun, Firecracker microVM, gVisor"** — 모델이 생성한 코드를 안전하게 실행하는 다섯 가지 옵션.
- **"Fresh vs Next.js vs Astro 2026 — islands architecture의 세 답"** — SSR 풀스택의 자리 다툼.
- **"Deno Deploy vs Cloudflare Workers vs Vercel Edge"** — Edge runtime 세 강자의 비교.
참고 / References
Deno 공식 자료
- Deno 공식 사이트 — [https://deno.com/](https://deno.com/) — 최신 버전, 변경 사항.
- Deno 매뉴얼 — [https://docs.deno.com/](https://docs.deno.com/) — 런타임·CLI·표준 라이브러리.
- Deno GitHub — [https://github.com/denoland/deno](https://github.com/denoland/deno) — issue·release notes.
- Deno blog (releases) — [https://deno.com/blog](https://deno.com/blog) — 메이저 버전별 변경 사항.
Deno 2 출시 자료
- "Deno 2.0" 발표 글 — Node 호환과 `package.json` 지원의 베팅.
- Deno 2 RFC와 디자인 노트 — `nodeModulesDir`, workspace 도입 배경.
JSR
- JSR 공식 — [https://jsr.io/](https://jsr.io/) — 패키지 검색, score, 문서.
- JSR docs — TS-native publishing, scope 관리.
- "Why JSR" 글 — Deno 팀의 동기, 디자인 결정.
Fresh
- Fresh 공식 — [https://fresh.deno.dev/](https://fresh.deno.dev/)
- Fresh 2 마이그레이션 가이드 — Fresh 1에서 2로 옮기는 방법.
- Preact 공식 — [https://preactjs.com/](https://preactjs.com/) — Fresh의 렌더링 엔진.
Deno KV
- Deno KV 문서 — `Deno.openKv()` API, 키 구조, atomic transaction.
- Deno KV blog post (GA 발표) — production-ready 선언.
- FoundationDB — Deno Deploy KV의 백엔드 기술.
Deno Deploy
- Deno Deploy — [https://deno.com/deploy](https://deno.com/deploy) — global isolate runtime.
- Deno Deploy 가격·제한 — 결제 플랜, per-key 제한, edge 제약.
Node.js (비교)
- Node.js 공식 — [https://nodejs.org/](https://nodejs.org/)
- Node `--experimental-strip-types` 문서 — TS 직접 실행.
- `node:test` 문서 — Node 22+ 기준의 native test runner.
Bun (비교)
- Bun 공식 — [https://bun.sh/](https://bun.sh/)
- Bun 런타임 호환 매트릭스 — Node API 호환 상태.
보안 / 권한 모델
- Deno permission system 문서 — `--allow-*` 플래그의 모든 옵션.
- OWASP supply chain security — npm/JS 생태계의 위협 모델.
- xz-utils 사건 회고 — 공급망 공격이 보안 모델 베팅에 미친 영향.
운영 채택 사례 (공개 글 기준)
- Netlify Edge Functions 엔지니어링 블로그의 Deno 도입 글.
- Supabase Edge Functions 아키텍처 — Deno 기반 런타임의 설계.
- Slack 자동화에서 Deno를 채택한 사례 글.
비판적 시각 / 회고
- "Why we did NOT pick Deno" 류의 startup 글 — 의도적으로 안 고른 회사들의 이유.
- APM auto-instrumentation의 한계에 대한 운영팀 글.
- Deno 2의 자기 부정에 대한 커뮤니티 반응 (forum, HackerNews, Reddit).
표준화 / WinterCG
- WinterCG — [https://wintercg.org/](https://wintercg.org/) — JS 런타임 간 호환 표준 그룹.
- Web-interoperable runtimes 명세 — Deno·Bun·Workers·Vercel이 따르는 표준.
현재 단락 (1/325)
Ryan Dahl은 2009년 Node를 만들었고, 2018년 JSConf EU에서 "Node에서 후회하는 10가지"라는 유명한 발표를 했다. 그리고 Deno를 만들었다. 보안은 ...