Deno 2 vs Bun 1.3 — 2026年Node.js替代运行时实战对比:TypeScript、速度与安全

Deno 2 vs Bun 1.3 — 2026年Node.js替代运行时实战对比:TypeScript、速度与安全

我实际安装了Deno 2.8.2和Bun 1.3.14,测量了启动时间、HTTP吞吐量、npm兼容性和安全模型。这是我会在哪种场景下选择哪个的具体结论。

2026年中期,JavaScript运行时的选择实际上缩减到了三个:Node.js、Bun、Deno。说实话,坚持使用Node.js的理由越来越少了。真正的问题是在Bun和Deno之间做选择。

我一直在观望这两个运行时。我知道Bun”很快”,也听说Deno 2大幅改善了Node.js兼容性。但在我自己的机器上实际运行之前,选择标准并不明确。这次我在临时沙箱中安装了Deno 2.8.2和Bun 1.3.14,提取了实际数据。

两个运行时,一句话总结

Bun的目标是将Node.js生态系统原封不动地带过来,同时大幅提升速度。现有的package.jsonnode_modules和npm工作流程都能直接使用。迁移成本低。

Deno 2是从头开始重新设计的运行时。它提出了新的惯例:基于权限的安全模型、URL导入、npm:指定符、JSR(JavaScript Registry)。Deno 2实现了与Node.js的完整后向兼容,但设计哲学不同。

两个工具运行相同的TypeScript代码,但它们来自完全不同的方向。

安装

# 安装Bun
curl -fsSL https://bun.sh/install | bash
bun --version  # 1.3.14

# 安装Deno
curl -fsSL https://deno.land/install.sh | sh
deno --version  # 2.8.2 (stable, aarch64-apple-darwin), TypeScript 6.0.3

两者都是单二进制文件安装。~/.bun/bin/bun集成了运行时、包管理器、打包器和测试运行器。Deno给你~/.deno/bin/deno。结构看起来相似,但Bun直接支持node_modules方式,而Deno默认使用基于URL的模块系统。

启动时间:Bun更快,但并非总是如此

我用一个对100,000个数字数组求和的简单TypeScript文件进行了测试。

# 冷启动(首次运行)
Bun:   0.243s
Deno:  0.067s

# 热启动(第2〜5次平均)
Bun:   0.013s
Deno:  0.026s

这个结果出乎意料。Bun并非总是更快。首次运行时,Deno快约3.6倍。Bun首次运行慢的原因可能是JavaScriptCore基于JIT编译器的初始化开销。热启动后,Bun约快2倍。

对于长期运行的服务器,Bun的热启动性能更有优势。但对于CLI工具或短脚本,Deno的响应性更好。

HTTP吞吐量:基本相当

我用Apache Bench直接测量(n=3000, c=30, 127.0.0.1)。

Bun Serve API:   23,794 RPS  (0.126s)
Deno.serve API:  22,594 RPS  (0.133s)

差距约5%。实际项目中这个差距几乎没有意义。两个运行时都比Node.js内置HTTP模块快得多,实际瓶颈来自网络或业务逻辑,而非运行时本身。

我不会仅凭HTTP性能来选择运行时。这些数字只是确认”两者都足够快”。

npm包兼容性:方式不同

这是实质差异最大的地方。

Bun:传统npm方式

bun add zod             # 91ms,创建node_modules
bun add lodash @types/lodash  # 651ms,安装35个包

bun add是一个比npm更快的包管理器。直接使用node_modules结构,迁移现有项目几乎不需要额外配置。

Denonpm:指定符方式

// 无需安装,直接导入
import { z } from "npm:zod@3";
import _ from "npm:lodash@4";

使用npm:指定符不需要单独安装步骤。首次运行时下载到Deno的全局缓存,之后可离线使用。没有node_modules一开始会觉得陌生,但克隆项目后无需任何安装步骤就能运行的优势很大。

当我写Bun Shell脚本指南时,Bun的npm兼容性让我能直接使用现有的实用工具库,没有任何障碍。Deno的npm:方式在脚本实验和新项目中更方便。

安全模型:这才是真正的区别

这是让我意识到自己低估了Deno的地方。

Deno:默认沙箱

# 尝试在没有权限的情况下读取文件
$ deno run deno-security.ts
Permission denied: Requires read access to "/etc/hosts"

# 明确授予权限
$ deno run --allow-read=/etc/hosts --allow-net=api.github.com deno-security.ts
File read success: ## Host Database ...
Network success: 200

Bun:开放模型

$ bun run bun-security.ts
File read (Bun, no restriction): ## Host Database ...

Bun像Node.js一样,默认可以访问文件系统、网络和环境变量。开发便利性高,但如果第三方包运行恶意代码,没有任何阻止手段。

Deno需要明确授予权限:--allow-read--allow-write--allow-net--allow-env--allow-run。在CI/CD或服务器环境中运行第三方代码时,Deno的沙箱是实质性的防线。

说实话,Deno的权限标志在开始时会有些麻烦。忘记--allow-net而使用fetch时遇到错误是常有的事,多踩几次坑才会习惯。对于来自Node.js的开发者,初期确实存在摩擦。

Node.js兼容性:现在两者都支持

在Deno 1.x时代,Node.js API兼容性是重大弱点。Deno 2改变了这一状况。

// 通过node:前缀使用标准模块
import { readFileSync, existsSync } from "node:fs";
import { join } from "node:path";
import { createHash } from "node:crypto";
import { EventEmitter } from "node:events";

我直接测试了这段代码,Bun和Deno都能正常运行。crypto.createHash("sha256")、EventEmitter、fs.existsSync全部通过。就像在Cloudflare Workers上运行Hono.js一样,Hono在Bun和Deno上都能正常工作。

TypeScript支持:版本差异值得关注

Bun 1.3.14:   TypeScript(基于Babel的转译器)
Deno 2.8.2:   TypeScript 6.0.3(V8 14.9.207.2)

两者都无需单独编译步骤就能运行TypeScript,但方式不同。

Bun不进行类型检查。只是将TypeScript转换为JavaScript后执行,这是其速度快的原因之一。

Deno使用TypeScript 6.0.3,支持通过deno check命令进行完整的类型验证。如果需要在CI中确保类型安全,Deno提供了更清晰的答案。

# Deno:带类型检查的执行
deno check main.ts    # 只检查类型错误
deno run main.ts      # 不检查类型,快速执行

# Bun:仅转译
bun run main.ts       # 始终跳过类型检查
bun typecheck         # 单独调用tsc

包生态系统:JSR vs npm

Deno 2还有jsr:指定符。JSR(JavaScript Registry)是Deno团队创建的新包注册中心,原生支持TypeScript,仅支持ESM。

// 使用JSR包
import { assertEquals } from "jsr:@std/assert@1";
import { serve } from "jsr:@hono/hono@4/deno";

个人认为JSR上发布的包质量很高,但与npm相比包的数量还很少。截至2026年,JSR的生态系统还在成长,大多数可立即使用的库仍然在npm上。

Bun直接使用npm生态系统,因此不存在这个问题。

我的选择标准

将测量数据整理如下:

项目Bun 1.3.14Deno 2.8.2
冷启动0.243s(慢)0.067s(快)
热启动0.013s(快)0.026s(中等)
HTTP RPS23,79522,594
包安装bun add 91msnpm:指定符(无需安装)
安全模型开放模型默认沙箱
Node.js兼容性非常高Deno 2大幅改善
TypeScript仅转译支持类型检查(TS 6.0.3)
包生态系统完整npmnpm + JSR

加速现有Node.js项目:Bun。迁移摩擦小,完整的npm支持。

新的TypeScript项目:Deno。类型安全、安全模型、无需安装的npm:指定符组合很简洁。

CLI工具或短脚本:Deno。冷启动快,单文件部署方便。

Cloudflare Workers / Edge:两者都与Hono配合良好。Cloudflare有自己的运行时,所以这里的差别不大。

运行第三方代码:Deno。在没有沙箱的环境中运行未知包存在真实风险。

我之前的误解

“Bun快X倍”的营销信息到处都是。实际上HTTP吞吐量只差5%。冷启动反而Deno更快。真正的差异在于安全模型、TypeScript类型检查方式和包管理哲学,而不是速度。

我对Deno 2 Node.js兼容性的改善也是在实际验证之前半信半疑。node:fsnode:cryptonode:events不需要任何标志就能正常工作,这一点确实令人印象深刻。

还有一些让我不满意的地方。Deno的--allow-*标志系统在开发初期会有摩擦。有时只有运行后才知道需要哪些权限,复杂应用的权限列表变长后管理也很繁琐。

内置测试运行器:真正的差异

两个运行时都内置了测试运行器,不需要Jest或Mocha。

Bun测试

// counter.test.ts
import { expect, test, describe } from "bun:test";

describe("Counter", () => {
  test("正确递增", () => {
    let count = 0;
    count++;
    expect(count).toBe(1);
  });
  
  test("异步也能工作", async () => {
    const result = await Promise.resolve(42);
    expect(result).toBe(42);
  });
});
bun test                     # 项目中的所有测试
bun test counter.test.ts     # 特定文件
bun test --watch             # 监视模式

bun:test与Jest兼容。现有Jest测试往往无需修改即可运行。类似于从Jest迁移到Vitest,迁移到Bun时describe/test/expect API是相同的。

Deno测试

// counter_test.ts
import { assertEquals } from "jsr:@std/assert@1";

Deno.test("正确递增", () => {
  let count = 0;
  count++;
  assertEquals(count, 1);
});

Deno.test("异步也能工作", async () => {
  const result = await Promise.resolve(42);
  assertEquals(result, 42);
});
deno test                    # 自动发现*_test.ts, test_*.ts
deno test counter_test.ts    # 特定文件
deno test --watch            # 监视模式

Deno以Deno.test()为基础。测试也遵循权限模型——访问文件系统的测试需要--allow-read。JSR的@std/assert提供类型安全的断言。

从Jest迁移的话,Bun的高兼容性占优势。新项目的话,Deno的风格也很简洁。

实际项目搭建对比

从头开始一个新项目时,具体有什么不同。

Bun项目初始化

mkdir my-api && cd my-api
bun init -y          # 生成package.json、tsconfig.json、index.ts
bun add hono         # 添加依赖
bun run index.ts     # 运行

生成的package.json和普通Node.js项目一样。CI中也可以用bun install && bun run build这样的现有脚本。

Deno项目初始化

mkdir my-api && cd my-api
deno init            # 生成main.ts、deno.json、main_test.ts

生成的deno.json:

{
  "tasks": {
    "dev": "deno run --watch --allow-net main.ts",
    "test": "deno test"
  },
  "imports": {
    "hono": "npm:hono@^4.7.0"
  }
}

deno.jsonimports字段负责包映射。没有node_modules,deno.lock固定版本。需要一些时间来适应,但理解后会觉得很整洁。

部署环境的差异

单一可执行文件编译

两者都可以编译为不需要运行时的单一二进制文件。

# Deno
deno compile --allow-net --output server main.ts
./server

# Bun
bun build --compile index.ts --outfile server
./server

对于分发CLI工具非常方便。Deno编译时指定--allow-*标志,同时也起到文档化二进制需求的作用。

Docker

两者都有官方Docker镜像,容器化都很简单。Deno需要在CMD中包含权限标志,这迫使你在基础设施层面明确权限设计。

何时使用,何时避免

比起抽象的对比,决策标准更有用。基于实测结果,按场景整理如下。

应该使用 Bun 的场景

  • 想提升现有 Node.js 服务的速度,同时把迁移成本降到最低。package.jsonnode_modules 可以照常工作。
  • 拥有大量基于 Jest 的测试资产。bun:test 兼容 Jest API,迁移负担小。
  • npm 依赖较深的服务。如果内部库或遗留包只存在于 npm,Bun 更稳妥。

应该避免 Bun 的场景

  • 在不可信环境中运行第三方代码。没有默认沙箱,文件系统和网络都是开放的。
  • 想在 CI 中把严格类型检查作为门禁。Bun 不做类型检查,需要单独调用 tsc

应该使用 Deno 的场景

  • 新的 TypeScript 项目。类型检查、默认沙箱和免安装的 npm: 指定符一次到位。
  • CLI 工具或短脚本。冷启动快,便于以单一二进制分发。例如把用 Node.js 内置 SQLite 构建本地数据工具的工作迁移到 Deno,就可以用权限标志收窄磁盘访问范围。
  • 在服务器或 CI/CD 中运行未知的第三方包。权限模型成为实质性的防御线。

应该避免 Deno 的场景

  • 深度依赖 npm 专属包的现有代码库。兼容性已改善,但部分原生插件仍有摩擦。
  • 团队难以承受管理权限标志的初期摩擦。复杂应用中 --allow-* 列表会变长。

如果还要一并设计类型安全的数据层,不妨在两种运行时上都验证一下Drizzle ORM 与 TypeScript 的组合。Drizzle 在 Bun 和 Deno 上表现一致。

来源与官方文档

本文的数值是我自己测量的,但运行机制和兼容性都对照各运行时的官方文档做了核实。

最后,我会怎么选

很难得出其中一个运行时明显更好的结论。“情况不同”这个陈腐的答案,这次确实来自实际数据。

对于我自己的自动化脚本和个人CLI工具,今后可能主要使用Deno。冷启动性能和npm:指定符的无安装特性在脚本工作中很方便。对于依赖大量npm包的团队项目或服务,Bun的兼容性更实用。

两个运行时都支持单一二进制编译、Docker和Hono。框架层基本上是可移植的。

继续使用Node.js的理由越来越少。无论走哪个方向,这两个替代选项在2026年标准下都已达到可用于生产的水平。

常见问题

Deno和Bun哪个更快?
取决于工作负载。冷启动(首次运行)Deno为0.067s,比Bun(0.243s)快约3.6倍;但热启动后Bun为0.013s,比Deno(0.026s)快2倍。HTTP吞吐量基本相当:Bun为23,794 RPS,Deno为22,594 RPS,仅差约5%,在实际项目中并无意义。
生产环境应该用Deno还是Bun?
如果是加速现有Node.js项目或依赖大量npm的服务,迁移成本低的Bun更实用。如果是新的TypeScript项目、CLI工具或运行第三方代码的环境,具备类型检查和默认沙箱的Deno更好。两者在2026年标准下都已达到可用于生产的水平。
从Node.js迁移到Bun或Deno容易吗?
Bun让现有的package.json、node_modules和npm工作流程直接运行,迁移成本非常低。Deno 2也能通过node:前缀让node:fs、node:crypto、node:events等无需任何标志即可运行,兼容性大幅改善。但Deno的权限标志(--allow-*)在初期会有摩擦。
Deno和Bun的安全模型有什么区别?
Bun像Node.js一样采用开放模型,默认可访问文件系统、网络和环境变量,因此无法阻止恶意第三方代码。Deno采用默认沙箱,需要明确授予--allow-read、--allow-net等权限,在CI/CD或服务器上运行第三方代码时,这成为实质性的防线。

阅读其他语言版本

这篇文章有帮助吗?

您的支持能帮助我创作更好的内容。请我喝杯咖啡吧。

关于作者

jw

Kim Jangwook

AI/LLM专业全栈开发者

凭借10年以上的Web开发经验,构建AI代理系统、LLM应用程序和自动化解决方案。分享Claude Code、MCP和RAG系统的实践经验。

返回博客列表