Deno 2 — JavaScript Runtime Thế Hệ Mới: Bảo Mật, TypeScript Native và Tương Thích NPM

Posted on: 4/26/2026 1:13:51 AM

2.6+Phiên bản ổn định mới nhất
100%TypeScript tích hợp sẵn
97%Tương thích NPM packages
0Config file bắt buộc

Trong thế giới JavaScript runtime, Node.js đã thống trị hơn 15 năm. Nhưng từ khi Deno 2.0 ra mắt cuối 2024 và liên tục cải tiến đến phiên bản 2.6 hiện tại, cuộc chơi đã thay đổi hoàn toàn. Deno không chỉ là "Node.js viết lại" — đây là runtime được thiết kế lại từ đầu bởi chính Ryan Dahl (cha đẻ Node.js), sửa triệt để những sai lầm thiết kế mà ông thừa nhận sau hơn một thập kỷ.

1. Tại sao cần Deno khi đã có Node.js?

Ryan Dahl trình bày "10 Things I Regret About Node.js" tại JSConf EU 2018, liệt kê các quyết định thiết kế sai lầm: không có security , hệ thống module dựa trên node_modules cồng kềnh, thiếu TypeScript native, và API không theo Web Standards. Deno ra đời để giải quyết tất cả những vấn đề này.

Triết lý thiết kế Deno

Secure by default — không có quyền truy cập file, network, hay environment variables cho đến khi developer cho phép rõ ràng. Đây là đảo ngược hoàn toàn so với Node.js, nơi mọi script đều có toàn quyền hệ thống.

2. Kiến trúc Deno Runtime

graph TB
    A[Deno CLI] --> B[V8 Engine]
    A --> C[Rust Core - Tokio]
    A --> D[TypeScript Compiler - swc]

    B --> E[JavaScript Execution]
    C --> F[Async I/O Runtime]
    D --> G[Type Checking + Transpilation]

    F --> H[File System]
    F --> I[Network]
    F --> J[Subprocess]

    K[Permission System] --> H
    K --> I
    K --> J

    L[Web Standard APIs] --> M[fetch, Request, Response]
    L --> N[WebSocket, Streams]
    L --> O[URL, TextEncoder/Decoder]

    style A fill:#e94560,stroke:#fff,color:#fff
    style K fill:#4CAF50,stroke:#fff,color:#fff
    style L fill:#2c3e50,stroke:#fff,color:#fff
    style B fill:#f8f9fa,stroke:#e94560,color:#2c3e50
    style C fill:#f8f9fa,stroke:#e94560,color:#2c3e50
    style D fill:#f8f9fa,stroke:#e94560,color:#2c3e50

Kiến trúc tổng quan Deno Runtime — V8 + Rust + Permission System

Deno được xây dựng bằng Rust thay vì C++ (như Node.js), sử dụng Tokio làm async runtime. Điều này mang lại memory safety và hiệu năng vượt trội. TypeScript được transpile bằng swc (viết bằng Rust), nhanh hơn 20-70x so với trình biên dịch TypeScript chính thức.

3. Hệ thống Permission — Bảo mật mặc định

Đây là điểm khác biệt lớn nhất của Deno. Mỗi chương trình chạy trong mà không có quyền gì cả:

# Không cho phép bất kỳ quyền nào — script chỉ tính toán thuần
deno run compute.ts

# Cho phép đọc file trong thư mục data/ và truy cập network đến api.example.com
deno run --allow-read=./data --allow-net=api.example.com app.ts

# Cho phép tất cả (không khuyến khích trong production)
deno run -A app.ts
Permission FlagMô tảVí dụ
--allow-readĐọc file system--allow-read=./config,./data
--allow-writeGhi file system--allow-write=./output
--allow-netTruy cập mạng--allow-net=api.github.com
--allow-envBiến môi trường--allow-env=API_KEY,NODE_ENV
--allow-runChạy subprocess--allow-run=git,npm
--allow-ffiForeign Function Interface--allow-ffi=./libcrypto.so
--allow-sysThông tin hệ thống--allow-sys=hostname,osRelease

Permission Sets trong Deno 2.5+

Từ Deno 2.5, bạn có thể định nghĩa Permission Sets trong deno.json — nhóm các permission lại thành profile có tên, tái sử dụng cho nhiều script. Tương tự khái niệm Security Policy trong .NET.

4. TypeScript Native — Không cần cấu hình

Deno hiểu TypeScript trực tiếp, không cần tsconfig.json, không cần ts-node, không cần build step:

// server.ts — chạy trực tiếp: deno run --allow-net server.ts
const handler = (request: Request): Response => {
  const url = new URL(request.url);

  if (url.pathname === "/api/health") {
    return Response.json({
      status: "ok",
      runtime: "deno",
      version: Deno.version.deno
    });
  }

  if (url.pathname === "/api/users" && request.method === "GET") {
    const users: Array<{ id: number; name: string }> = [
      { id: 1, name: "Anh Tú" },
      { id: 2, name: "Minh Khoa" },
    ];
    return Response.json(users);
  }

  return new Response("Not Found", { status: 404 });
};

Deno.serve({ port: 8000 }, handler);
console.log("Server running on http://localhost:8000");

Chú ý: API Deno.serve() sử dụng Web Standard Request/Response — giống hệt API của Cloudflare Workers, Bun, và các edge runtime khác. Code viết cho Deno có thể chạy trên các platform này với rất ít thay đổi.

4.1 Type Checker tsgo — Tốc độ kiểm tra kiểu cải thiện hàng chục lần

Deno 2.6 tích hợp tsgo — type checker thử nghiệm viết bằng Go, nhanh hơn đáng kể so với trình kiểm tra TypeScript chuẩn. Điều này đặc biệt hữu ích cho các dự án lớn nơi type checking mất hàng phút:

# Dùng tsgo cho type checking nhanh hơn
deno check --unstable-tsgo main.ts

# So sánh tốc độ
time deno check main.ts          # ~8.2s (TypeScript chuẩn)
time deno check --unstable-tsgo main.ts  # ~0.9s (tsgo)

5. Hệ thống Module — URL Import + NPM Compatibility

Deno hỗ trợ 3 cách import module:

// 1. Import từ URL (Deno-native, dùng JSR registry)
import { Application } from "jsr:@oak/oak@17";

// 2. Import từ NPM (tương thích hoàn toàn từ Deno 2.0)
import express from "npm:express@5";
import { PrismaClient } from "npm:@prisma/client";

// 3. Import từ node: protocol (Node.js built-in modules)
import { readFile } from "node:fs/promises";
import { createServer } from "node:http";
graph LR
    A[Source Code] --> B{Import Type?}
    B -->|jsr:| C[JSR Registry]
    B -->|npm:| D[NPM Registry]
    B -->|node:| E[Node.js Compat Layer]
    B -->|https://| F[URL Import]

    C --> G[Deno Cache
~/.cache/deno] D --> G E --> H[Built-in Polyfills] F --> G G --> I[V8 Execution] H --> I style A fill:#e94560,stroke:#fff,color:#fff style G fill:#f8f9fa,stroke:#e94560,color:#2c3e50 style I fill:#2c3e50,stroke:#fff,color:#fff

Luồng resolve module trong Deno — hỗ trợ JSR, NPM, Node.js built-in và URL

Không còn node_modules

Deno cache module vào một thư mục global (~/.cache/deno), không tạo node_modules trong project. Điều này tiết kiệm disk space đáng kể — một dự án trung bình giảm từ 200-500MB xuống gần 0MB trong thư mục project. Tuy nhiên, bạn vẫn có thể bật "nodeModulesDir": "auto" trong deno.json nếu cần tương thích với tooling cũ.

5.1 JSR — JavaScript Registry thế hệ mới

JSR (jsr.io) là registry mới do team Deno xây dựng, thiết kế cho TypeScript-first. Khác với NPM, JSR yêu cầu package publish source TypeScript gốc và tự động tạo type declarations, documentation, và compatibility layers:

// deno.json — cấu hình đơn giản, không cần package.json
{
  "tasks": {
    "dev": "deno run --watch --allow-net --allow-read server.ts",
    "test": "deno test --allow-read",
    "lint": "deno lint",
    "fmt": "deno fmt"
  },
  "imports": {
    "@std/http": "jsr:@std/http@1",
    "@std/assert": "jsr:@std/assert@1",
    "hono": "jsr:@hono/hono@4"
  }
}

6. Công cụ tích hợp — All-in-One Toolchain

Deno đi kèm mọi công cụ phát triển cần thiết, không cần cài thêm bất kỳ package nào:

Công cụLệnh DenoTương đương Node.js
Test runnerdeno testJest / Vitest / Mocha
Formatterdeno fmtPrettier
Linterdeno lintESLint
Type checkerdeno checktsc
Bundlerdeno compileesbuild / webpack
Task runnerdeno tasknpm scripts
Package runnerdxnpx
Security auditdeno auditnpm audit
Documentationdeno docTypeDoc
Benchmarkingdeno benchbenchmarkjs
REPLdeno replnode (REPL)
// user_service_test.ts — Deno test với BDD style
import { assertEquals, assertRejects } from "jsr:@std/assert";

interface User {
  id: number;
  name: string;
  email: string;
}

function validateEmail(email: string): boolean {
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}

Deno.test("validateEmail - email hợp lệ", () => {
  assertEquals(validateEmail("tu@anhtu.dev"), true);
  assertEquals(validateEmail("admin@example.com"), true);
});

Deno.test("validateEmail - email không hợp lệ", () => {
  assertEquals(validateEmail("invalid"), false);
  assertEquals(validateEmail("@example.com"), false);
  assertEquals(validateEmail("user@"), false);
});

Deno.test({
  name: "fetch API - trả về dữ liệu đúng format",
  permissions: { net: ["jsonplaceholder.typicode.com"] },
  async fn() {
    const res = await fetch("https://jsonplaceholder.typicode.com/users/1");
    const user: User = await res.json();
    assertEquals(typeof user.id, "number");
    assertEquals(typeof user.name, "string");
  },
});

7. dx — npx cho Deno

Deno 2.6 giới thiệu dx — công cụ chạy binary từ NPM và JSR packages mà không cần cài đặt global:

# Chạy Vite trực tiếp
dx vite create my-vue-app

# Chạy package từ JSR
dx jsr:@anthropic/claude-code

# Chạy Prisma CLI
dx prisma migrate dev

# Tạo project Hono
dx create-hono my-api

8. Deno Deploy — Serverless Runtime trên Edge

Deno không chỉ là runtime local — Deno Deploy là nền tảng serverless chạy code trên 35+ edge locations toàn cầu, với cold start dưới 10ms:

graph TB
    A[Developer] -->|git push| B[GitHub Repository]
    B -->|Auto Deploy| C[Deno Deploy Platform]

    C --> D[Edge Location
Singapore] C --> E[Edge Location
Tokyo] C --> F[Edge Location
Frankfurt] C --> G[Edge Location
US East] D --> H[Users APAC] E --> I[Users Japan] F --> J[Users Europe] G --> K[Users Americas] C --> L[Deno KV
Global Database] C --> M[Deno Cron
Scheduled Tasks] C --> N[Deno Queues
Message Queue] style A fill:#e94560,stroke:#fff,color:#fff style C fill:#2c3e50,stroke:#fff,color:#fff style L fill:#f8f9fa,stroke:#e94560,color:#2c3e50 style M fill:#f8f9fa,stroke:#e94560,color:#2c3e50 style N fill:#f8f9fa,stroke:#e94560,color:#2c3e50

Deno Deploy — Serverless edge deployment với KV, Cron, và Queues tích hợp

// API đơn giản trên Deno Deploy với KV storage
const kv = await Deno.openKv();

Deno.serve(async (request: Request) => {
  const url = new URL(request.url);

  if (url.pathname === "/api/visit") {
    // Atomic increment view counter
    const key = ["visits", new Date().toISOString().slice(0, 10)];
    await kv.atomic()
      .sum(key, 1n)
      .commit();

    const result = await kv.get<bigint>(key);
    return Response.json({
      date: key[1],
      visits: Number(result.value ?? 0n)
    });
  }

  if (url.pathname === "/api/cache" && request.method === "POST") {
    const { key, value, ttl } = await request.json();
    await kv.set(["cache", key], value, {
      expireIn: ttl * 1000
    });
    return Response.json({ cached: true });
  }

  return new Response("Deno Deploy API", { status: 200 });
});

9. So sánh Deno 2.6 vs Node.js 22 vs Bun 1.2

Tiêu chíDeno 2.6Node.js 22Bun 1.2
Ngôn ngữ coreRust + V8C++ + V8Zig + JavaScriptCore
TypeScriptNative, không cần configCần ts-node/tsxNative
SecuritySandbox mặc định, granular permissionsExperimental permission modelKhông có
NPM Support97%+ tương thích100% (native)~95% tương thích
Built-in ToolsTest, Lint, Fmt, Bench, Doc, AuditTest runner (basic)Test, Bundler
HTTP Server~120K req/s~80K req/s~160K req/s
Cold Start~25ms~40ms~10ms
Web Standardsfetch, Request, Response, Streams, WebSocket nativefetch (từ v18), partialfetch, partial
Package RegistryJSR + NPMNPMNPM
Edge DeployDeno Deploy (tích hợp)Cần third-partyKhông có
Single Executabledeno compileSEA (thử nghiệm)bun build --compile

Khi nào nên chọn Deno?

Chọn Deno khi ưu tiên bảo mật (chạy code third-party), cần TypeScript native không config, muốn all-in-one toolchain, hoặc cần deploy lên edge. Chọn Node.js khi cần hệ sinh thái NPM 100% và có nhiều legacy code. Chọn Bun khi ưu tiên tốc độ thuần trên mọi benchmark.

10. Deno với Hono — Xây API Production

Kết hợp Deno với Hono framework tạo nên stack API hiệu năng cao, type-safe, và portable:

import { Hono } from "jsr:@hono/hono@4";
import { cors } from "jsr:@hono/hono@4/cors";
import { logger } from "jsr:@hono/hono@4/logger";
import { validator } from "jsr:@hono/hono@4/validator";

type Bindings = {
  DB: Deno.Kv;
};

const app = new Hono<{ Bindings: Bindings }>();

app.use("*", logger());
app.use("/api/*", cors({ origin: "https://anhtu.dev" }));

app.get("/api/posts", async (c) => {
  const kv = await Deno.openKv();
  const entries = kv.list<{ title: string; slug: string }>({
    prefix: ["posts"]
  });

  const posts = [];
  for await (const entry of entries) {
    posts.push(entry.value);
  }

  return c.json({ data: posts, total: posts.length });
});

app.post("/api/posts",
  validator("json", (value, c) => {
    if (!value.title || typeof value.title !== "string") {
      return c.json({ error: "Title is required" }, 400);
    }
    return value as { title: string; body: string };
  }),
  async (c) => {
    const { title, body } = c.req.valid("json");
    const kv = await Deno.openKv();
    const id = crypto.randomUUID();

    await kv.set(["posts", id], {
      id, title, body,
      createdAt: new Date().toISOString()
    });

    return c.json({ id, title }, 201);
  }
);

Deno.serve({ port: 3000 }, app.fetch);

11. WebAssembly Source Phase Imports

Deno 2.6 hỗ trợ Source Phase Imports cho WebAssembly — import module Wasm trực tiếp trong code TypeScript mà không cần fetch runtime:

// Import Wasm module dưới dạng source
import source wasmModule from "./optimized_algo.wasm";

// Instantiate với imports
const instance = await WebAssembly.instantiate(wasmModule, {
  env: {
    log: (ptr: number, len: number) => {
      // Xử lý logging từ Wasm
    }
  }
});

// Gọi exported function
const result = instance.exports.fibonacci(42);
console.log(`Fibonacci(42) = ${result}`);

12. Migration từ Node.js sang Deno

Bước 1 — Thêm deno.json
Tạo deno.json với "nodeModulesDir": "auto" để Deno tự tạo node_modules cho các NPM package. Đổi scripts sang "tasks".
Bước 2 — Chuyển imports
Thay require() bằng ESM import. Deno hỗ trợ CJS qua npm: specifier nhưng khuyến khích ESM. Các built-in Node.js dùng prefix node: (ví dụ import fs from "node:fs").
Bước 3 — Cập nhật test
Chuyển Jest/Mocha sang Deno.test() hoặc giữ nguyên nếu dùng Vitest (Deno tương thích). Thêm permission flags cho test cần network/file access.
Bước 4 — CI/CD
Thay npm ci && npm test bằng deno test --allow-read --allow-net. Deno cài đặt bằng một dòng: curl -fsSL https://deno.land/install.sh | sh.
Bước 5 — Deploy
Deploy lên Deno Deploy (zero-config), Docker container, hoặc compile thành single executable với deno compile cho self-hosting.

13. Khi nào KHÔNG nên dùng Deno?

Hạn chế cần lưu ý

  • Native addons — Các package dùng C++ native addons (node-gyp) có thể không tương thích. Ví dụ: bcrypt (dùng bcryptjs thay thế), sharp (dùng Wasm build).
  • Ecosystem maturity — Một số framework lớn (NestJS, AdonisJS) chưa hỗ trợ Deno chính thức, dù có thể chạy qua compatibility layer.
  • Enterprise tooling — Nếu team đang dùng nặng npm workspaces, Lerna, hoặc Nx cho monorepo, migration sẽ phức tạp hơn.
  • Serverless platforms — AWS Lambda, Azure Functions chưa hỗ trợ Deno runtime native (cần custom runtime hoặc compile thành binary).

14. Tổng kết

Deno 2 không còn là thí nghiệm — đây là runtime production-ready với triết lý thiết kế hiện đại: bảo mật mặc định, TypeScript native, Web Standards first, và all-in-one toolchain. Với khả năng tương thích NPM 97%+, JSR registry mới, và Deno Deploy cho edge deployment, Deno đang trở thành lựa chọn nghiêm túc cho các dự án JavaScript/TypeScript mới.

Nếu bạn đang bắt đầu dự án mới và không bị ràng buộc bởi hệ sinh thái Node.js legacy, Deno xứng đáng là runtime đầu tiên cần cân nhắc — đặc biệt khi bảo mật và developer experience là ưu tiên hàng đầu.

Nguồn tham khảo