Deno Deployは、2026年10月9日の発表から6か月で運用を終えます。DenoのチームがCloudflareに合流するためで、移行先として案内されているのはCloudflare Workersです。この記事では、終了までの日程と未公表の点を公式発表で確かめたうえで、移行先をWorkers・Node.js・Bun・Denoの自前運用で比べます。後半は、Deno.serveのコードをWorkersへ書き換える手順、Fresh 2の設定、Deno KVのデータの書き出しと投入、Deno.cronのCron Triggers化を、コピーして使えるコードで示します。
まとめ:Deno Deployは2027年4月ごろ終了しKVのデータ移送が最大の作業
Deno Deployの停止は、発表日から数えて2027年4月ごろです。正確な最終日はまだ公表されていません。Denoのランタイム自体も、1年間の保守のあとで開発が止まります。
移行先は、ほとんどの案件でCloudflare Workersが第一候補になります。Web標準のRequestとResponseで書かれたコードは、入口をexport default { fetch }に変えるだけで動く部分が多いからです。手間がかかるのはコードではなくデータです。新しいDeno DeployのKVは外部から接続できないため、アプリの中に書き出し用のルートを足すか、S3への継続バックアップから取り出す必要があります。
Deno KVを使っているなら、今月中に書き出しの経路を作ってください。メモリ128MBを超える処理や子プロセスを使う処理があるなら、WorkersではなくNode.jsのコンテナへ移します。
2026年10月9日の発表で決まったDeno Deploy・ランタイム・JSRの今後
発表はDenoの公式ブログ「Deno is joining Cloudflare」と、Cloudflare側の同名の記事の2本です。Deno Deployの扱いが書かれているのはDeno側の記事だけです。
Deno Deployは発表から6か月で停止し最終日の日付は未公表という現状
Deno側の記事には「Deno Deploy will continue operating for six months before shutting down.」とあります。期間で書かれていて、日付の記載はありません。10月9日から6か月を数えると2027年4月上旬です。
有料プランの利用者には、Cloudflare Workersへの移行支援が提供されます。支援の中身や申し込み方法は、10月13日時点でまだ出ていません。無料プランの利用者は自力で移す前提で計画を立てるのが安全です。
Denoランタイムは1年間の月次保守後に開発終了しJSRは運用を継続
ランタイムは今後1年間、月次のリリースでバグ修正とセキュリティ修正が続きます。その後、Denoチームとしての開発は終了です。コードはオープンソースのまま残り、引き継ぐ開発者を歓迎するとしています。
パッケージレジストリのJSRは止まりません。基盤はCloudflareへ移り、運用は続く予定です。jsr:で読み込んでいるパッケージは、移行後もnpm互換の形で取得できます。V8のRustバインディングであるrusty_v8も保守が続き、Cloudflareのランタイムworkerdへの統合を目指すと書かれています。
Deploy Classicの2026年7月停止と現行Deno Deployの違い
Deno Deployには2つの世代があります。Deno Deployの公式ドキュメントによると、旧版のDeploy Classic(dash.deno.com)とsubhosting v1 APIは2026年7月20日に停止済みです。今回終了が決まったのは、その移行先だった現行版(console.deno.com)です。
同じドキュメントの比較表では、現行版はKVとcronに対応する一方、キュー(kv.enqueue)は非対応です。現行版で動いているアプリはkv.enqueueを使えないため、Deno Deploy固有の機能として移す対象はKVとcronの2つに絞れます。
Deno Deployの移行先をWorkers・Node.js・Bun・自前運用で比較
移行先の候補は4つです。保守の見通しとコードの書き換え量の両方で比べます。
移行先4択の比較表と2027年10月以降の保守期間から見た選び方
| 移行先 | 書き換え量 | KVの移し先 | 2027年10月以降 | 向く案件 |
|---|---|---|---|---|
| Cloudflare Workers | 入口とDeno名前空間API | KV・Durable Objects | Cloudflareが継続 | API・SSR・Freshアプリ |
| Node.js(コンテナ) | Deno名前空間APIと依存の解決 | Redis・PostgreSQLなど | Node.jsの保守周期どおり | 重い処理・子プロセス |
| Bun(コンテナ) | Node.jsとほぼ同じ | Redis・SQLiteなど | Bunの開発元次第 | 起動速度を重視する案件 |
| Deno自前運用 | ほぼ不要 | セルフホストのdenokv | 保守終了・自己責任 | 移行までのつなぎ |
実務ではまずWorkersを検討し、128MBのメモリ上限などの制約に当たる処理だけをNode.jsへ回す、という順番で十分です。BunのNode.js互換の範囲はBun 1.4のNode.js互換の実測範囲で整理しています。
Cloudflare Workersの無料枠10ミリ秒とPaidプラン月5ドルの制約
Workersの制限一覧では、無料のWorkers FreeはHTTPリクエストあたりのCPU時間が10ミリ秒です。Workers Paidは既定30秒、設定で最大5分まで延ばせます。メモリはどちらも1 isolateあたり128MB、Workerのサイズは非圧縮で64MiBが上限です。
料金はWorkersの料金ページのとおり、Paidが月5ドルからで、月1,000万リクエストとCPU時間3,000万ミリ秒を含みます。Freeは1日10万リクエストまでです。業務で使うAPIはFreeの10ミリ秒に収まらないことが多いので、Paidを前提に見積もります。Workers全体の料金の考え方はCloudflare Workersの対応言語・無料枠・料金のまとめにあります。
Denoの自前運用は修正が止まる2027年までのつなぎにとどめる理由
Denoをdeno compileやDockerで自社のサーバーへ移せば、コードはほぼそのまま動きます。ただし約1年後に公式のセキュリティ修正が止まります。インターネットに公開するサーバーで、修正の出ないランタイムを使い続けるのは避けるべきです。
自前運用を選ぶのは、Workersへの書き換えが期限に間に合わない場合だけにします。その場合も、2027年10月ごろまでに2回目の移行を終える計画を最初から組んでおきます。
Deno.serveをWorkersのfetchハンドラーとHonoへ書き換える手順
Deno Deployのコードは、Web標準のAPIで書かれた部分とDeno固有のAPIを呼ぶ部分に分かれます。前者はそのまま使え、書き換えるのは後者です。
Deno.serveをexport default fetchへ移す設定と最小コード
移行前のDeno Deployのコードが次のような形だとします。
// main.ts(Deno Deploy)
Deno.serve((req) => {
const url = new URL(req.url);
if (url.pathname === "/health") return new Response("ok");
return Response.json({ greeting: Deno.env.get("GREETING") });
});
Workersでは、fetchメソッドを持つオブジェクトをexport defaultします。環境変数はDeno.envではなく、第2引数のenvから読みます。
// src/index.ts(Cloudflare Workers)
export interface Env {
GREETING: string;
}
export default {
async fetch(req: Request, env: Env): Promise<Response> {
const url = new URL(req.url);
if (url.pathname === "/health") return new Response("ok");
return Response.json({ greeting: env.GREETING });
},
} satisfies ExportedHandler<Env>;
設定ファイルのwrangler.jsoncは次のとおりです。
{
"name": "my-app",
"main": "src/index.ts",
"compatibility_date": "2026-10-01",
"vars": { "GREETING": "hello" }
}
WorkersのNode.js互換のドキュメントによると、compatibility_dateが2026-08-04以降ならnodejs_compatは既定で有効です。npm:で読み込んでいたパッケージの多くは、package.jsonに移せば動きます。ただしchild_processは読み込めるだけの空の実装で、実行はできません。
HonoでDeno Deploy上に書いていたなら、作業はさらに少なくなります。Deno.serve(app.fetch)をexport default appに変え、Deno.envをHonoの公式手順にあるc.envへ置き換えます。
Deno.env・Deno.openKv・Deno.cronの置き換え先一覧
| Deno Deployでの書き方 | Workersでの置き換え先 |
|---|---|
Deno.serve(handler) |
export default { fetch } |
Deno.env.get("X") |
env.X(vars・シークレット) |
Deno.openKv() |
KV・Durable Objects |
Deno.cron(...) |
crons設定とscheduledハンドラー |
Deno.readTextFile()の読み込み |
静的アセットかビルド時の埋め込み |
jsr:@std/...の読み込み |
npx jsr addでnpm互換として追加 |
置き換え先の候補を洗い出すには、grep -rn "Deno\." src/でDeno名前空間の呼び出しを全件拾うのが早道です。件数が見えれば、移行の工数もほぼ決まります。
Fresh 2をCloudflareのViteプラグインでWorkersへ載せる設定
Fresh 2はビルドにViteを使うため、Workers向けのプラグインを足すだけで載せられます。Fresh公式のCloudflare Workers向け手順の内容は次のとおりです。
deno install --allow-scripts npm:@cloudflare/vite-plugin npm:wrangler
// vite.config.ts
import { defineConfig } from "vite";
import { fresh } from "@fresh/plugin-vite";
import { cloudflare } from "@cloudflare/vite-plugin";
export default defineConfig({
plugins: [fresh(), cloudflare()],
});
// server.js(Workersの入口)
import server from "./_fresh/server.js";
export default {
fetch: server.fetch,
};
wrangler.jsoncのmainは./server.jsを指すようにします。注意点は、ルートのハンドラーでDeno.openKv()などを呼んでいる箇所です。Freshの部分は動いても、その呼び出しはWorkersで失敗するので、前の表に沿って置き換えます。Fresh 2の構成はDeno Freshとアイランドアーキテクチャの解説を、Vite上で同じ考え方を取るHonoXはHonoXの特徴と採用判断を参照してください。
Deno KVのデータを書き出しWorkers KVとDurable Objectsへ移送
移行で最も時間がかかるのはこの章の作業です。データの量にかかわらず、書き出しの経路を先に作っておきます。
新Deno DeployではKV Connectで外から読めない制約と書き出し用ルート
Node.jsからKVを使う方法のドキュメントには、外部から接続するKV Connectは「新しいDeno DeployのKVでは提供していない」とあります。Classic時代のように@deno/kvで手元から読み出すことはできません。
確実なのは、稼働中のアプリに書き出し専用のルートを一時的に足す方法です。トークンで保護し、カーソルで1,000件ずつ返します。
// export_kv.ts(Deno Deployのアプリに一時的に追加する)
const kv = await Deno.openKv();
const TOKEN = Deno.env.get("EXPORT_TOKEN");
export async function exportKv(req: Request): Promise<Response> {
if (!TOKEN || req.headers.get("authorization") !== `Bearer ${TOKEN}`) {
return new Response("forbidden", { status: 403 });
}
const cursor = new URL(req.url).searchParams.get("cursor") || undefined;
const iter = kv.list({ prefix: [] }, { limit: 1000, cursor });
const rows: string[] = [];
for await (const e of iter) {
rows.push(JSON.stringify({ key: e.key, value: e.value }));
}
// 0件になったら空のカーソルを返して終了の合図にする
return new Response(rows.join("\n") + "\n", {
headers: {
"content-type": "application/x-ndjson",
"x-next-cursor": rows.length ? iter.cursor : "",
},
});
}
手元からは、カーソルが空になるまで繰り返し取得します。
cursor=""
: > kv_export.ndjson
while :; do
curl -s -D headers.txt -G -H "Authorization: Bearer $EXPORT_TOKEN" \
--data-urlencode "cursor=$cursor" "$APP_URL/__export_kv" >> kv_export.ndjson
cursor=$(grep -i '^x-next-cursor:' headers.txt | cut -d' ' -f2 | tr -d '\r')
[ -z "$cursor" ] && break
done
この例は、キーと値が文字列・数値・真偽値・プレーンなオブジェクトだけの前提です。bigintはJSON.stringifyで例外になり、Uint8ArrayやDeno.KvU64は形が崩れます。使っている型を先に確かめ、該当するなら変換処理を足してください。書き出しが終わったらルートとトークンは削除します。
S3継続バックアップとdenokvのpitrコマンドで手元に複製する方法
もう1つの経路が、ダッシュボードから設定する継続バックアップです。KVのバックアップのドキュメントのとおり、KVタブの「Backup」でS3またはGoogle Cloud Storageのバケットを指定すると、状態が「Active」になって書き込みが続きます。
バケットに溜まったデータは、denokvのリポジトリにあるツールで手元のSQLiteへ同期できます。
denokv --sqlite-path ./denokv.sqlite pitr sync --s3-bucket your-bucket --s3-prefix <バックアップのプレフィックス>/
denokv --sqlite-path ./denokv.sqlite pitr list
同期したファイルはdenokv serveで立ち上げれば@deno/kvから読めるので、前節と同じ書き出し処理を手元で回せます。本番のアプリに手を入れたくない場合や、移行当日まで差分を取り続けたい場合はこちらが向いています。
結果整合のWorkers KVと強い整合のDurable Objectsへの振り分け基準
移し先は2つに分かれます。Workers KVの仕組みのページによると、Workers KVは結果整合で、他の拠点に反映されるまで60秒以上かかることがあり、アトミックな操作には向かないとされています。書き込みのドキュメントでは、同じキーへの書き込みは1秒に1回までです。
判断の基準は、Deno KVでkv.atomic()を使っていたかどうかです。在庫や残高のようにcheckで版を確かめて更新していたデータは、SQLiteを使うDurable Objectsへ移します。transactionSyncでまとめて更新でき、SQLも使える構成です。設定値やキャッシュのように読む回数が多く更新の少ないデータは、Workers KVで足ります。
キーの並び順にも注意が必要です。Deno KVのキーは["post", 9]のような型付きの配列で、数値は数値の大小で並ぶ仕組みです。Workers KVのキーは文字列なので、post:9とpost:10は文字列として比べられ、順序が入れ替わります。範囲指定で一覧を取っていた処理は、ゼロ埋めするか、Durable ObjectsのSQLで並べ直します。
wrangler kv bulk putで1万件ずつ投入するJSON変換スクリプト
Workers KVへ入れる分は、書き出したNDJSONを一括投入用のJSONに変えます。一括投入は1回1万件までで、キーは512バイトまでです。
// to_bulk.mjs(Node.jsで実行)
import { readFileSync, writeFileSync } from "node:fs";
const lines = readFileSync("kv_export.ndjson", "utf8").split("\n").filter(Boolean);
const pairs = lines.map((line) => {
const { key, value } = JSON.parse(line);
return { key: key.join(":"), value: JSON.stringify(value) };
});
const tooLong = pairs.filter((p) => Buffer.byteLength(p.key) > 512);
if (tooLong.length) throw new Error(`512バイト超のキーが${tooLong.length}件あります`);
for (let i = 0; i < pairs.length; i += 10000) {
writeFileSync(`bulk_${i / 10000}.json`, JSON.stringify(pairs.slice(i, i + 10000)));
}
npx wrangler kv namespace create APP_KV
npx wrangler kv bulk put bulk_0.json --binding=APP_KV --remote
コマンドの一覧はWranglerのKVコマンドのリファレンスにあります。投入後は件数と、いくつかのキーの値を元のデータと突き合わせてから切り替えます。
Deno.cronの定期処理をCron Triggersのscheduledへ写す設定
Deno DeployのcronのドキュメントとWorkersのCron Triggersのドキュメントは、どちらも時刻をUTCで扱います。cron式は書き換えずにそのまま移せます。
複数のDeno.cronを1つのscheduledハンドラーで振り分ける実装例
Deno Deployで、日本時間の午前3時と15分ごとの2つの処理を登録していたとします。
Deno.cron("cleanup", "0 18 * * *", () => cleanup());
Deno.cron("sync", "*/15 * * * *", () => syncOrders());
Workersでは、wrangler.jsoncにcron式を並べ、1つのscheduledハンドラーでcontroller.cronを見て分岐します。
// wrangler.jsonc に追加
"triggers": { "crons": ["0 18 * * *", "*/15 * * * *"] }
// src/index.ts
export default {
async fetch(req: Request, env: Env) { /* 省略 */ return new Response("ok"); },
async scheduled(controller: ScheduledController, env: Env, ctx: ExecutionContext) {
if (controller.cron === "0 18 * * *") ctx.waitUntil(cleanup(env));
if (controller.cron === "*/15 * * * *") ctx.waitUntil(syncOrders(env));
},
} satisfies ExportedHandler<Env>;
違いは2点です。Deno.cronのbackoffScheduleで指定していた再試行は、Cron Triggersの設定にありません。失敗時に再試行したい処理はCloudflare Queuesへ投げ、キュー側の再試行に任せます。もう1点は登録数で、Cron Triggersはアカウントあたり無料で5件、Paidで250件までです。
Deno Deploy移行を今すぐ始める案件と年明けでよい案件の線引き
期限まで約6か月あっても、すべての案件が同じ緊急度ではありません。
Deno KVの利用・独自ドメイン・Fresh固有処理の有無で着手時期を決める基準
次のどれかに当てはまる案件は、今月中に着手します。
- Deno KVに業務データがある(書き出し経路の用意と、Workers KVかDurable Objectsかの設計が要る)
kv.atomic()で整合性を守っている処理がある(Durable Objectsへの作り直しになる)- 独自ドメインで公開している(DNSと証明書の切り替え、停止期間の調整が要る)
- Freshのルートハンドラーから
Deno.*のAPIを多く呼んでいる
一方、KVを使わずHonoやDeno.serveで書いた外部API中継のようなアプリは、書き換えが数時間で済みます。年明けに着手しても間に合いますが、2027年3月には切り替えを終える計画にしておきます。停止日が公表されていない以上、4月に入ってからの作業は避けるべきです。
メモリ128MB・子プロセス・長時間処理が要件ならWorkersを見送る判断
次の処理を含むアプリは、Workersへ移しません。
- 1回の処理でメモリを128MB以上使う(大きなCSVや画像の変換など)
- 外部コマンドを子プロセスで呼ぶ(
child_processは動かない) - 1リクエストのCPU時間が5分を超えうる
これらはNode.jsのコンテナへ移し、軽いAPIだけをWorkersに置く分割が現実的です。Denoの権限設計やLTSを前提に組んだ構成をどこまで残すかは、DenoとFreshの開発環境・LTS選定の解説と照らして決めます。移行先の選定からデータ移行、切り替え当日の手順までをまとめて計画したい場合は、システムマイグレーション・リプレイスで対応範囲を確認できます。
Deno Deployの終了日・移行支援・ランタイムについてよくある質問
2026年10月13日時点の公式情報をもとに答えます。
Deno Deployはいつ終了しますか?
Denoの公式ブログには「6か月運用したあとで停止する」とだけ書かれており、日付は示されていません。2026年10月9日の発表から数えると2027年4月上旬になります。停止日が後から公表される可能性はありますが、それを待たずに2027年3月までに切り替えを終える計画が安全です。最新の告知はDeno Deployのダッシュボードと公式ブログで確認してください。
Cloudflareの移行支援は誰が受けられますか?
公式ブログでは、移行支援の対象は「Cloudflare Workersへ移る有料顧客」とされています。無料プランの利用者への支援は書かれていません。支援の具体的な内容や申し込み方法は、10月13日時点で公表されていません。有料プランを契約している場合でも、Deno KVの書き出しのようにアプリの中身に関わる作業は自社側で進める前提で準備しておくのが確実です。
Denoランタイムはもう使わないほうがよいですか?
すぐに使えなくなるわけではありません。今後1年間は月次でバグ修正とセキュリティ修正が出ます。ただし、その後の開発はDenoチームとしては終わるため、新規のシステムをDenoで作るのは避けるのが無難です。CLIツールや社内スクリプトのように影響範囲が小さい用途は、1年の間にNode.jsやBunへ移す計画を立てれば足ります。
JSRに公開したパッケージはどうなりますか?
JSRは運用を続けると明記されています。基盤がCloudflareへ移るだけで、公開済みのパッケージやjsr:での読み込みは引き続き利用可能です。Workersへ移したアプリからJSRのパッケージを使う場合は、npx jsr addでnpm互換の形として追加します。
Deno KVのデータをClassicのように@deno/kvで読み出せますか?
現行のDeno DeployのKVは、外部からのKV Connectに対応していません。@deno/kvで直接読み出す方法はClassic時代のデータベース向けです。現行版では、アプリに書き出し用のルートを足すか、ダッシュボードでS3かGoogle Cloud Storageへの継続バックアップを設定し、denokvツールで手元に同期してから読み出します。
関連記事
- Deno Freshとは|Preactとアイランドアーキテクチャの軽量Webフレームワーク:Workersへ移すFresh 2アプリの構成を確かめるときに。
- DenoとFreshの開発環境セットアップ|インストール・権限設計・LTS選定:移行までの間、手元のDeno環境を保つときに。
- Cloudflare Workersとは?対応言語・無料枠・使い方・料金を最新版で総まとめ:移行先のWorkersの料金と無料枠の確認に。
- Bun 1.4とは?Rust実装への移行とNode.js互換の実測範囲を実装目線で解説:WorkersでなくBunへ移す場合の互換範囲の確認に。
- Supabase Edge Functionsとは:Deno実行環境とデプロイ・シークレット・課金単位:Denoで書いた関数を別の基盤で動かす選択肢として。