返回首页
⚙️ 后端 / 架构

Deno 2.5 + KV 2.0 全栈实战 2026:边缘 Serverless 运行时新王

Deno 2.5 正式发布,KV 2.0 + Queues GA + Fresh 3.0。本文完整实战 Deno 全栈:TypeScript 原生、KV 分布式存储、Fresh 框架、部署到 Deno Deploy,30 分钟上线一个生产级 SaaS。

Deno · Deno KV · Serverless · 边缘计算 · Fresh · TypeScript · 全栈 · Hono
��

今日技术简讯

📰 技术简讯 · 2026-09-06

今日聚合 6 条热门技术内容(中文素材优先)。

⚙️ 后端 / 架构

1. Deno 2.5 正式发布

  • 链接https://deno.com/blog/v2.5
  • 来源:Deno
  • 摘要:Deno 2.5 推出 KV 2.0(分布式键值存储 GA)+ Queues GA + 全栈框架 Fresh 3.0。

2. Cloudflare Workers + Durable Objects 新增 SQL

3. Kubernetes 1.34 推出 Serverless 模式

🎨 前端 / Web

4. SvelteKit 3 + Svelte 6 GA

🤖 AI / LLM

5. LangChain.js v1.0 GA

🚀 独立开发 / OPC

6. Stripe 推出 Lifetime Deal 工具


数据来源:掘金 / InfoQ 中文 / 即刻 / 少数派 / HN 采集日期:2026-09-06 (UTC+8)

��

今日深度文

Deno 2.5 + KV 2.0 全栈实战 2026:边缘 Serverless 运行时新王

2026 年的后端运行时市场,Deno 已经不再是"小众实验品" — 它用 5 年时间完成了 Node.js 用了 10 年才走完的路:内置 TypeScript、内置测试、内置格式化、内置 lint、内置 KV / Queues / Cron。本文的目的是:30 分钟内,用 Deno + Fresh + Deno KV,从零上线一个生产级 SaaS


一、为什么 Deno 2.5 是 Serverless 时代的答案

1.1 Serverless 的三大痛点

云厂商的 Serverless(FaaS)虽然火,但开发者苦不堪言:

  1. 冷启动:Lambda / Cloud Functions 首次调用 500ms – 2s
  2. Vendor Lock-in:每个云厂商一套 API,迁移成本极高
  3. 本地开发体验差:必须用厂商 CLI / 模拟器,无法在本地"完全复刻云端"

Deno 2.5 通过三个特性同时解决这三个问题:

  • 冷启动 < 50ms:V8 Snapshot + 预编译 wasm,单函数启动比 Node.js 还快
  • 跨云兼容:同一份代码可以跑在 Deno Deploy / Cloudflare / AWS / 本地
  • 本地即生产deno run 直接跑,没有任何特殊运行时

1.2 Deno vs Node.js vs Bun(2026 年 9 月)

维度 Deno 2.5 Node.js 22 Bun 1.3
TypeScript 原生 ✅ 内置 ❌ 需要 ts-node / swc ✅ 内置
标准库 ✅ 官方丰富 ✅ npm 包 ⚠️ 部分
内置 KV / DB ✅ Deno KV 2.0 ❌ 无 ❌ 无
包管理器 ✅ deno install ⚠️ npm (慢) ✅ bun install (快)
npm 兼容 ✅ 完全 ✅ 原生 ✅ 完全
冷启动 ⭐⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐
生态成熟度 ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐

2026 年的现实选择

  • 想用 npm 生态 + 性能:Bun 1.3
  • 想极致稳定 + 最大生态:Node.js 22
  • 想"零配置全栈":Deno 2.5(自带 KV / Queues / Cron / Fresh)

二、Deno KV 2.0:分布式键值存储 GA

2.1 核心概念

Deno KV 是 Deno 内置的分布式键值存储,类似 Redis 但更强大:

  • 强一致性:默认 eventual consistency,可配置 strong
  • 全球分布式:基于 Deno Deploy 的边缘节点
  • 事务支持:ACID 事务,跨 key 原子操作
  • 二级索引:支持 list / atomic 操作

2.2 基础 CRUD

// kv.ts
const kv = await Deno.openKv();

// Set
await kv.set(["users", "u_123"], {
  name: "Alice",
  email: "alice@example.com",
  createdAt: Date.now(),
});

// Get
const user = await kv.get(["users", "u_123"]);
console.log(user.value);

// Delete
await kv.delete(["users", "u_123"]);

// List(带 prefix)
const users = kv.list({ prefix: ["users"] });
for await (const entry of users) {
  console.log(entry.key, entry.value);
}

2.3 原子事务

// 转账:从 A 账户扣 100,加到 B 账户
const result = await kv.atomic()
  .check({ key: ["accounts", "A"], versionstamp: accountA.versionstamp })
  .set(["accounts", "A"], { balance: accountA.balance - 100 })
  .set(["accounts", "B"], { balance: accountB.balance + 100 })
  .set(["transactions", crypto.randomUUID()], {
    from: "A",
    to: "B",
    amount: 100,
    timestamp: Date.now(),
  })
  .commit();

if (!result.ok) {
  throw new Error("Transaction failed (A's balance changed)");
}

2.4 二级索引(KV 2.0 新增)

// 主键:users/u_123
// 二级索引:users/by_email/alice@example.com -> u_123

await kv.atomic()
  .set(["users", "u_123"], user)
  .set(["users", "by_email", user.email], "u_123")
  .commit();

// 通过 email 查询
const userIdEntry = await kv.get(["users", "by_email", "alice@example.com"]);
const userEntry = await kv.get(["users", userIdEntry.value]);

三、Fresh 3.0:Islands 架构 SSR 框架

3.1 什么是 Fresh

Fresh 是 Deno 官方的全栈 Web 框架,灵感来自 Astro:

  • 默认 SSR:服务端渲染,SEO 友好
  • Islands 架构:只对交互组件做客户端 hydration
  • 零 JS by default:首屏 0 KB JavaScript

3.2 创建一个 Fresh 项目

deno run -A -r https://fresh.deno.dev my-saas
cd my-saas
deno task start

3.3 项目结构

my-saas/
├── deno.json          # 配置 + 任务
├── main.ts            # 入口
├── dev.ts             # 开发模式
├── routes/            # 文件路由(Next.js 风格)
│   ├── index.tsx      # /
│   ├── api/
│   │   └── users.ts   # /api/users
│   └── dashboard.tsx  # /dashboard
├── islands/           # 客户端交互组件
│   └── Counter.tsx
├── components/        # SSR-only 组件
│   └── Layout.tsx
├── static/            # 静态资源
└── utils/
    └── kv.ts          # Deno KV 封装

3.4 路由示例

// routes/index.tsx
import { Handlers, PageProps } from "$fresh/server.ts";

interface Data {
  users: { name: string; email: string }[];
}

export const handler: Handlers<Data> = {
  async GET(_req, ctx) {
    const kv = await Deno.openKv();
    const users: any[] = [];
    for await (const entry of kv.list({ prefix: ["users"] })) {
      if (entry.key[1] !== "by_email") users.push(entry.value);
    }
    return ctx.render({ users });
  },
};

export default function Home({ data }: PageProps<Data>) {
  return (
    <main class="max-w-4xl mx-auto p-6">
      <h1 class="text-3xl font-bold">用户列表</h1>
      <ul class="mt-4 space-y-2">
        {data.users.map((u) => (
          <li class="p-3 bg-gray-50 rounded">
            <strong>{u.name}</strong> — {u.email}
          </li>
        ))}
      </ul>
    </main>
  );
}

3.5 Island 组件(客户端交互)

// islands/Counter.tsx
import { useState } from "preact/hooks";

export default function Counter() {
  const [count, setCount] = useState(0);
  return (
    <div class="flex items-center gap-3">
      <button
        onClick={() => setCount(count - 1)}
        class="px-3 py-1 bg-red-100 rounded"
      >
        -
      </button>
      <span class="text-xl font-bold">{count}</span>
      <button
        onClick={() => setCount(count + 1)}
        class="px-3 py-1 bg-green-100 rounded"
      >
        +
      </button>
    </div>
  );
}

在路由中使用:

import Counter from "../islands/Counter.tsx";

export default function Home() {
  return (
    <main>
      <h1>My SaaS</h1>
      <Counter />  {/* 只这个组件会被 hydrate */}
    </main>
  );
}

四、完整实战:30 分钟做一个 SaaS

我们要做一个极简的 Todo SaaS,功能:

  • 用户注册 / 登录
  • 每个用户有自己的 Todo 列表
  • 支持实时同步(Deno Queues)

4.1 用户认证(基于 KV)

// utils/auth.ts
import { crypto } from "std/crypto/mod.ts";

export async function hashPassword(password: string): Promise<string> {
  const salt = "static-salt-2026";
  const data = new TextEncoder().encode(password + salt);
  const hash = await crypto.subtle.digest("SHA-256", data);
  return btoa(String.fromCharCode(...new Uint8Array(hash)));
}

export async function createUser(email: string, password: string) {
  const kv = await Deno.openKv();
  const userId = crypto.randomUUID();
  const passwordHash = await hashPassword(password);

  // 原子操作:检查 email 不存在 + 创建用户 + 建二级索引
  const result = await kv.atomic()
    .check({ key: ["users", "by_email", email], versionstamp: null })
    .set(["users", userId], {
      email,
      passwordHash,
      createdAt: Date.now(),
    })
    .set(["users", "by_email", email], userId)
    .commit();

  if (!result.ok) throw new Error("Email already exists");
  return userId;
}

export async function login(email: string, password: string) {
  const kv = await Deno.openKv();
  const userIdEntry = await kv.get(["users", "by_email", email]);
  if (!userIdEntry.value) return null;

  const userEntry = await kv.get(["users", userIdEntry.value]);
  const user = userEntry.value as any;

  const passwordHash = await hashPassword(password);
  if (passwordHash !== user.passwordHash) return null;

  return userIdEntry.value;
}

4.2 Todo CRUD

// utils/todos.ts
const kv = await Deno.openKv();

export async function listTodos(userId: string) {
  const todos: any[] = [];
  for await (
    const entry of kv.list({ prefix: ["todos", userId] })
  ) {
    todos.push({ id: entry.key[2], ...entry.value });
  }
  return todos;
}

export async function createTodo(userId: string, title: string) {
  const todoId = crypto.randomUUID();
  await kv.set(["todos", userId, todoId], {
    title,
    completed: false,
    createdAt: Date.now(),
  });
  return todoId;
}

export async function toggleTodo(userId: string, todoId: string) {
  const entry = await kv.get(["todos", userId, todoId]);
  const todo = entry.value as any;
  if (!todo) throw new Error("Todo not found");

  await kv.set(["todos", userId, todoId], {
    ...todo,
    completed: !todo.completed,
  });
}

export async function deleteTodo(userId: string, todoId: string) {
  await kv.delete(["todos", userId, todoId]);
}

4.3 API 路由

// routes/api/todos.ts
import { Handlers } from "$fresh/server.ts";
import { listTodos, createTodo } from "../../utils/todos.ts";
import { getCurrentUser } from "../../utils/auth.ts";

export const handler: Handlers = {
  async GET(req) {
    const userId = await getCurrentUser(req);
    if (!userId) return new Response("Unauthorized", { status: 401 });
    const todos = await listTodos(userId);
    return Response.json(todos);
  },

  async POST(req) {
    const userId = await getCurrentUser(req);
    if (!userId) return new Response("Unauthorized", { status: 401 });

    const { title } = await req.json();
    if (!title) return new Response("Title required", { status: 400 });

    const id = await createTodo(userId, title);
    return Response.json({ id });
  },
};

4.4 部署到 Deno Deploy

# 1. 安装 deployctl
deno install -A -r https://deno.land/x/deploy/deployctl.ts

# 2. 登录(Deno Deploy 会打开浏览器)
deployctl login

# 3. 一键部署
deployctl deploy --project=my-saas main.ts

部署后自动获得:

  • ✅ 全球 CDN(边缘节点 200+)
  • ✅ HTTPS 自动配置
  • ✅ KV 自动扩容(无需配置)
  • ✅ 免费额度:1M 请求/月 + 1GB KV 存储

五、Deno Queues:异步任务队列

Deno 2.5 新增 Queues GA,类似 AWS SQS 但开箱即用。

5.1 发送任务

const kv = await Deno.openKv();
const queue = await kv.enqueue("send-email", {
  delay: 5000, // 5 秒后执行
  keysIfUndelivered: [["email-failures", messageId]],
});

5.2 处理任务(listenQueue)

// main.ts
import { listenQueue } from "deno:kv";

listenQueue(async (payload) => {
  if (payload === "send-email") {
    await sendWelcomeEmail();
  } else if (payload.type === "send-email-to") {
    await sendEmail(payload.to);
  }
});

六、生产环境最佳实践

6.1 配置 deno.json

{
  "tasks": {
    "dev": "deno run -A --watch main.ts",
    "build": "deno run -A dev.ts build",
    "start": "deno run -A main.ts",
    "test": "deno test -A",
    "lint": "deno lint",
    "fmt": "deno fmt"
  },
  "imports": {
    "fresh": "jsr:@fresh/core@^3.0.0",
    "preact": "npm:preact@^10.22.0",
    "@preact/signals": "npm:@preact/signals@^1.3.0",
    "std/": "jsr:@std/"
  },
  "fmt": {
    "lineWidth": 100,
    "indentWidth": 2,
    "semiColons": true,
    "singleQuote": false
  },
  "lint": {
    "rules": {
      "tags": ["recommended"]
    }
  },
  "nodeModulesDir": "auto"
}

6.2 性能优化

// 1. KV 连接复用
const kv = await Deno.openKv();

// 2. 批量读取(避免循环 await)
const entries = await kv.getMany([
  ["users", "u_1"],
  ["users", "u_2"],
  ["users", "u_3"],
]);

// 3. 用 watch 监听变化(实时同步)
kv.watch([["todos", userId]]);  // 监听当前用户的 todos

6.3 安全建议

// main.ts
import { load } from "std/dotenv/mod.ts";

await load({ export: true });

// 强制生产环境必须设置关键环境变量
if (Deno.env.get("DENO_ENV") === "production") {
  if (!Deno.env.get("JWT_SECRET")) {
    throw new Error("JWT_SECRET required in production");
  }
}

七、未来展望:Deno + AI

2026 年的一个趋势:Deno 正在成为 AI Agent 运行时的首选:

  • Python 互操作:Deno 2.5 原生支持 python -m,可直接调用 PyTorch
  • Deno KV:天然适合 Agent 状态管理
  • 边缘部署:Agent 在用户附近运行,延迟 < 50ms
// AI Agent 示例(伪代码)
const llm = await import("npm:@anthropic-ai/sdk");

const agent = new Agent({
  llm: new llm.Anthropic(),
  tools: [searchTool, calculatorTool],
  state: kv,  // 直接用 Deno KV 作为 Agent 状态存储
});

await agent.run("帮我订明天下午 3 点的会议室");

八、结语

Deno 2.5 + KV 2.0 + Fresh 3.0 已经构成一个完整的全栈 Serverless 方案

  • 运行时:Deno(V8 + TypeScript 原生)
  • 存储:Deno KV(分布式、强一致、免费)
  • 框架:Fresh(Islands 架构、首屏 0 KB)
  • 部署:Deno Deploy(全球边缘、零配置)
  • 队列:Deno Queues(异步任务)
  • 定时任务:Deno Cron

30 分钟,从 0 到生产。这就是 Deno 的承诺。


参考资料

�� 同主题文章

⚙️ 后端 / 架构 分类更多