フレームワーク

Deno Freshとは?Fresh 2.3の仕組み・アイランドのJS量とDeno開発終了発表後の採用判断

Deno Freshとは?Fresh 2.3の仕組み・アイランドのJS量とDeno開発終了発表後の採用判断

Fresh(フレッシュ)は、Denoの開発チームが生んだフルスタックのWebフレームワークです。ページはサーバーでHTMLに描画し、ボタンやフォームなど動かす部分(島)のJavaScriptだけをブラウザへ送ります。最新の安定版は2026年4月28日公開の2.3.3で、2.0からはViteプラグインとして動く構成に変わりました。2026年には開発体制も大きく動いています。6月にDeno社から独立したGitHub組織へ移り、10月9日にはDenoチーム全体のCloudflare合流と、Deno Deployの終了が発表されました。この記事では、Freshの仕組みと書き方を2.3.3の実物で確かめ、配信されるJSの量を測ったうえで、2026年10月時点で採用してよい条件を整理します。

まとめ:Fresh 2.3の配信JSとDeno開発終了予定を踏まえた採用判断

  • Freshは「サーバー描画+島だけhydrate」のアイランドアーキテクチャを採るフレームワークで、UIはPreactで書きます。
  • 最新安定版は2.3.3(2026年4月28日)です。2.0.0は2025年9月9日に正式リリースされ、リリースノートで「Viteプラグインになった」と明記しています。Viteなしで動かす旧Builderはレガシー扱いです。
  • 2.3.3の雛形で測ると、島を置かないページの<script>は0件でした。島を1つ置くと3ファイル・計46,518バイト(gzip換算で約18.3KB)を読み込みます。
  • Denoチームは2026年10月9日にCloudflareへの合流を発表しました。Deno Deployは6か月の運用ののち終了し、Denoランタイムの開発は1年間の保守リリースのあと終わります。
  • Freshは独立組織freshframeworkへ移り、次のFresh 3(アルファ)はNode.jsなどDeno以外でも動く設計に作り直されています。
  • 判断:既存のFreshアプリは2.3へ上げ、デプロイ先をDeno Deploy以外へ移します。1年以上運用する新規案件ではAstroなどを優先します。HonoXはアルファ段階の破壊的変更を許容できる場合に限って検討し、Fresh 3は正式版の公開後に評価します。

Deno Freshの定義と2026年10月時点の開発体制

公式ドキュメントはFreshを「Web標準の上に作られた、小さく速く拡張しやすいフルスタックWebフレームワーク」と説明しています(Fresh公式ドキュメント)。ルーティング、サーバー描画、データ取得、フォーム処理、ミドルウェアをひととおり備え、TypeScriptとJSXをDenoでそのまま扱えます。公式サイトは2026年6月にfresh.deno.devからusefresh.devへ移りました。

Fresh 2.3.3が安定版、Fresh 3はアルファ段階

版の流れは次のとおりです。日付はGitHub Releasesとnpmの公開日時(UTC)で確かめました。

版 公開日 位置づけ
1.7.3 1系の最終版 Viteなし・fresh.gen.ts方式
2.0.0 2025年9月9日 正式版・Viteプラグイン化
2.2.0 2025年11月18日 マイナー更新
2.3.3 2026年4月28日 最新の安定版
3.0.0-alpha.202610031718 2026年10月8日 npmの@frsh/freshで配布

2.x系の一覧はfreshframework/freshのReleases、JSRの@fresh/coreでも最新は2.3.3です。2.3.3のあと半年間、2系の新しい版は出ていません。

Deno社から独立したfreshframework組織

2026年6月3日、メンテナーのLuca Casonato氏がGitHub Discussionsの告知で、FreshをDenoとは別のGitHub組織へ移したと発表しました。同じ告知で、本人とMarvin Hagemeister氏がDeno社を離れたこと、今後のFreshは「Vite-only」になること、Nitroを使ってNode.jsやCloudflare WorkersなどDeno以外にも配備できるようにする計画が示されています。旧リポジトリgithub.com/denoland/freshは、現在freshframework/freshへ転送されます。

アイランドアーキテクチャの仕組み:既定はJSゼロ、島だけhydrate

Freshはすべてのページをサーバーで描画し、クライアントのJavaScriptを既定では送りません。対話が必要な部品だけをislands/フォルダ(またはroutes/内の(_islands)フォルダ)に置くと、その部品だけがブラウザでhydrate(イベントを結びつけて動かすこと)されます。ページ全体をhydrateするSPAとは逆に、動かす箇所を足していく考え方です。サーバー描画とクライアント描画の判断軸はCSRとSSRの違いと使い分けで、アイランドという設計そのものとAstroでの実装はアイランドアーキテクチャとは?仕組みとAstro 7の実装・JS量の実測、PPRとの違いで扱っています。

// islands/Counter.tsx(init が生成する島から装飾と型宣言を簡略化)
import type { Signal } from "@preact/signals";
import { Button } from "../components/Button.tsx";

export default function Counter(props: { count: Signal<number> }) {
  return (
    <div>
      <Button onClick={() => props.count.value -= 1}>-1</Button>
      <p>{props.count}</p>
      <Button onClick={() => props.count.value += 1}>+1</Button>
    </div>
  );
}

島に渡せるpropsと渡せない値

島のpropsはサーバーでシリアライズしてHTMLに埋め込み、ブラウザで復元します。そのため渡せる値が決まっています(Serialization)。

  • 渡せる:文字列・数値・真偽値・bigint・null・undefined、配列、プレーンオブジェクト、Date、URL、RegExp、Map、Set、Uint8Array、Temporalの各型、Preactのシグナル、サーバーで描画したJSX
  • 渡せない:関数とクロージャ、クラスのインスタンス、Symbol、WeakMap・WeakSet、Promiseやストリーム

つまずきやすいのは、onClick={() => ...}のようなイベントハンドラーを親ページから島へ渡す書き方です。ハンドラーは島の中で定義します。同じシグナルを複数の島へ渡すと、ブラウザ側でも同じインスタンスになり、島どうしで状態を共有できます。ブラウザ専用のAPIを使う島は、fresh/runtimeのIS_BROWSERでサーバー描画時の実行を避けます。

Fresh 2.3.3の配信JSを実測:島なしページは0件、島1つで3ファイル

「既定はJSゼロ」が実際にどうなるかを、2026年10月28日にmacOS上のDeno 2.9.8で確かめました。deno run -Ar jsr:@fresh/initで生成した雛形(Fresh 2.3.3・Preact 10.29.8・Vite 7.3.7)に島を持たない/aboutを足し、deno task buildのあとdeno serveで本番ビルドを起動してHTMLとアセットを取得しています。

ページ・ファイル サイズ gzip
/about(島なし)の<script> 0件 –
/(Counter島1つ)の<script> 1件 –
client-entry(Fresh実行部) 34,669B 13,089B
preact.module 11,031B 4,662B
fresh-island__Counter 818B 531B
島1つの合計 46,518B 約18.3KB

島なしのページは、CSS 1ファイル(1,825B)以外に何も読み込みませんでした。島を1つ置くと、HTML末尾のモジュールスクリプトがboot({Counter}, …)を呼び、シリアライズ済みのprops(シグナルの初期値3)を渡します。重いのは島本体(818B)ではなく、Fresh実行部とPreactの計約45KBです。島を置いたページでは、この2ファイルが島本体とは別に読み込まれると見積もっておきます。実際の転送量は依存関係、ビルド設定、圧縮、ブラウザキャッシュで変わります。

もう1点、deno serveで起動した本番ビルドは、Accept-Encoding: gzipを付けて要求してもContent-Encodingを付けずに返しました。アセットにはcache-control: public, max-age=31536000, immutableが付きます。圧縮は前段のCDNやリバースプロキシで掛ける前提で構成します。

Fresh 2のUI実装とPreact 10系の依存関係

FreshのビューはPreactで書きます。JSX、props、フックの書き方はReactとほぼ同じで、状態管理には@preact/signalsを使います。Preact公式サイトは本体のサイズを3kBと表記しています(Preact)。

版には注意が要ります。Preact本体は2026年9月30日に11.0.0を出し、10月27日の11.1.0が最新です。一方、Fresh 2.3.3の雛形はnpm:preact@^10.29.1を指定しており、入るのは10系(今回は10.29.8)です。Preact 11へ上げたのはFresh 3の開発ブランチで、10月3日のコミットで依存を更新しています。Fresh 2のアプリでPreact 11専用の機能を前提にしないでください。

ReactとPreactの違い(互換性とバンドルサイズ)

React向けのライブラリはpreact/compat経由で動かします。Fresh 2のViteプラグインはreactやreact-domをpreact/compatへ自動で割り当てるため、npmのパッケージを通常どおり入れられます(Fresh 2.0ベータの公式記事)。ただしReactの内部実装に依存するライブラリは動かないことがあるので、主要な依存は採用前に動作を確かめます。Preact単体の定義、10系と11系の違い、compatでReact資産を移す手順はPreactとは?Reactとの違い・導入手順・compat移行と採用判断で整理しています。

Fresh 2のプロジェクト構成とルーティングの書き方

新規プロジェクトはdeno run -Ar jsr:@fresh/initで作ります。2.3.3のinitは、Tailwind・VS Code設定・Dockerの追加を--tailwind・--vscode・--dockerで選べます。生成されたファイルは次のとおりでした。

components/Button.tsx
islands/Counter.tsx        # 島(ブラウザでも動く部品)
routes/_app.tsx           # <html> の外枠
routes/index.tsx          # /
routes/api/[name].tsx     # /api/:name
static/                   # 画像・CSSなど
client.ts                 # 全ページで読み込むクライアント入口
main.ts                   # サーバー入口(new App())
utils.ts                  # define ヘルパー
vite.config.ts            # plugins: [fresh()]
deno.json

Denoのインストール、権限フラグ、LTSの選び方を含む環境づくりはDenoとFreshの開発環境セットアップで手順を追えます。

new App()とfsRoutes()で組むサーバー側の入口

Fresh 2では、main.tsでnew App()を作り、.use()でミドルウェア、.get()でルートを登録し、.fsRoutes()でファイルベースのルートを差し込みます(App)。ミドルウェアはctxを1つ受け取り、ctx.next()で次へ渡します。雛形のmain.tsを短くすると次のとおりです。

import { App, staticFiles } from "fresh";
import { type State } from "./utils.ts";

export const app = new App<State>();

app.use(staticFiles());

// ミドルウェアは ctx を1つ受け取る
app.use(async (ctx) => {
  ctx.state.shared = "hello";
  return await ctx.next();
});

app.get("/api2/:name", (ctx) => new Response(`Hello, ${ctx.params.name}!`));

// routes/ 配下のファイルをルートとして差し込む
app.fsRoutes();

routes/とislands/のファイル配置とURLの対応

routes/のファイルパスがそのままURLになります。routes/about.tsxは/about、routes/blog/[slug].tsxは/blog/:slug、(folder)はURLに出ないグループです。ページはutils.tsのdefine.page()で書くと型が付きます。

// routes/about.tsx(島を持たないページ=JSは送られない)
import { define } from "@/utils.ts";

export default define.page(() => {
  return (
    <main>
      <h1>About</h1>
      <p>This is the about page.</p>
    </main>
  );
});

Viteプラグイン化で変わった開発とビルドの流れ

Fresh 1.xは「ビルド不要」が売りでした。2.0の途中で方針が変わっています。2025年9月2日のベータ告知は、Viteを任意で使え、Viteなしでも使えると書いていました(Fresh 2.0 Graduates to Beta)。ところが9月9日の2.0.0のリリースノートは「Fresh is officially a vite plugin now」と明記し、ドキュメントもViteを使わないBuilderを「Viteプラグインが出る前のアルファ期に使っていたもの」と位置づけています。2.3.3のinitにはBuilderで生成する--builderが残っていますが、6月の告知はViteなしのFreshをやめる意向を示しているので、新しく作るならVite構成を選びます。

作業 deno.json のタスク 中身
開発サーバー deno task dev vite(島はHMR対応)
本番ビルド deno task build vite build → _fresh/
本番起動 deno task start deno serve -A _fresh/server.js
Freshの更新 deno task update jsr:@fresh/update

公式トップは今も「設定ファイルもビルドもnode_modulesも要らない」と書いています。ただ、それはファイル1つでサーバーを書く場合の話です。initの雛形ではnode_modulesが作られ(今回75MB)、本番前にvite buildが要ります(今回18秒)。_fresh/はGitに入れません。見返りとして、ルートを必要時に読み込む方式とDenoのJSX precompileで起動が速くなりました。ベータ告知によると、Fresh公式サイトの起動時間は86msから8msへ短くなっています。

Fresh 1.xから2への移行で書き換える箇所

1.xのプロジェクトは自動では2.xになりません。deno run -Ar jsr:@fresh/updateで$fresh/server.tsのimportやミドルウェアの書式はある程度置き換わります。構成ファイルは手で直します(Migration Guide)。

観点 Fresh 1.x Fresh 2.x
import元 $fresh/server.ts fresh(jsr:@fresh/core)
開発・ビルド dev.ts vite.config.ts+client.ts
設定・マニフェスト fresh.config.ts・fresh.gen.ts 削除
ハンドラー・ミドルウェア (req, ctx) (ctx)
エラーページ _404.tsx・_500.tsx _error.tsx に統合
本番起動 deno run -A main.ts deno serve -A _fresh/server.js

ハマりやすいのはデプロイ側です。Vite構成へ移行した場合は、ビルド時に本番用の入口が生成されるため、起動対象をmain.tsから_fresh/server.jsへ変更します。実際のファイル削除やタスクの書き換えの順序はDenoとFreshの開発環境セットアップの移行手順に沿って進めてください。

デプロイ先の選び方:Deno Deploy終了とCloudflare Workers・Node.js

Denoは2026年10月9日、Deno is joining Cloudflareで、Denoチーム全体がCloudflareに加わると発表しました。決まったことは次の4点です。

  • Denoランタイムは、今後1年間はバグ修正とセキュリティ更新を月次でリリースし、その後は開発を終える(オープンソースとしては残る)
  • Deno Deployは6か月運用したのち終了し、有料顧客にはCloudflare Workersへの移行支援を提供する
  • JSRは運用を続け、基盤をCloudflareへ移す
  • 発表本文にFreshへの言及はない

Freshのドキュメントは10月28日時点でも、Deno Deployを推奨のデプロイ先として案内しています(Deploy to Deno Deploy)。ほかの選択肢はdeno compile、Docker、Cloudflare Workersです。Workersへは@cloudflare/vite-pluginをvite.config.tsに足し、_fresh/server.jsのfetchを書き出す入口ファイルを置けば載せられます。ルートのハンドラーでDeno.openKv()などDeno固有のAPIを呼んでいる箇所はWorkersで動かないので、置き換えが要ります。設定ファイルの全文とKV・cronの移し方はDeno Deploy終了と移行手順:Cloudflare WorkersへのコードとKV・cronの移し方にまとめました。Deno自体をやめてBunやNode.jsへ移す場合の比較はDeno Bun 比較:開発終了が決まったDenoからBun・Node.jsへ移す判断とコードで扱っています。

Fresh 3は、Deno依存を外す方向で作り直されています。開発ブランチはVite 8とNitro 3の上に書き直されており、npmの@frsh/freshでアルファを配布しています。10月17日にはLuca Casonato氏が「Fresh 3はNode、Deno、そのほかNitroがビルド対象にできるランタイムで動く」と答えました。正式版の時期は示されていません。Nitroのプリセットの考え方はNitroとは?Nuxtを支えるサーバーエンジンの仕組みとv3移行の判断軸が参考になります。

Freshを採用する条件と見送る場面

2026年10月時点では、既存アプリの移行と長期運用する新規案件で採用方針を分けます。

  • 既存のFresh 1.xアプリ:2.3へ上げ、デプロイ先をCloudflare WorkersかDockerへ移します。公式のCloudflare Workers向け手順はVite構成(2.x)が前提なので、Deno Deployの終了に合わせて移すなら2.3が出発点です。
  • 既存のFresh 2アプリ:Deno KVなどDeno固有APIの使用箇所を洗い出し、Deno Deployの停止前に移します。Fresh 3は追わず、正式版が出てから評価します。
  • 1年以上運用する新規案件:Fresh 2では始めません。Denoランタイムの開発は発表から1年で終わり、Fresh 3では作り直しが入るためです。2026年6月2日時点のFresh 3の比較資料(fresh2-comparison.md)では、new App()のビルダー、static/フォルダ、defineヘルパー、cors・csrfなどの組み込みプラグインがFresh 3に無いと整理されています。
  • 短期の社内ツールや検証:Fresh 2で問題ありません。島なしページのJSが0件になる性質は、管理画面のような静的寄りのUIで効きます。

Next.js・Astro・HonoXとの使い分け

同じ「サーバー描画中心」のフレームワークとの違いは次の表のとおりです。

観点 Fresh 2 Astro HonoX Next.js
UIライブラリ Preact固定 React・Vue等を混在可 hono/jsx・React等 React
島の扱い islands/に置く client:ディレクティブ islands/に置く Client Component境界(島とは別方式)
主な実行環境 Deno Node.js・各種アダプター Workers・Node.js等 Node.js・Vercel
向く案件 Deno前提の小中規模 コンテンツ主体のサイト Workers上のAPI+画面 大規模なReactアプリ

コンテンツが多いサイトならAstroが素直です(AstroとReactの違いと使い分け)。Workersに載せる前提で同じ島の考え方を取りたいならHonoXが近い選択肢ですが、HonoXのREADMEがアルファ段階と明記しており、同じメジャー版の中でも破壊的変更が入ります(HonoXとは?Hono×Viteのメタフレームワークの使い方とIslands・デプロイ・採用判断【v0.1.62】)。Reactのエコシステムを丸ごと使う大規模アプリはNext.jsに分があります。

よくある質問

Fresh 2.0は正式リリースされていますか?

はい。2.0.0は2025年9月9日に正式版として公開されました。その1週間前の9月2日に出たのはベータです。最新の安定版は2026年4月28日の2.3.3です。

Denoの開発終了でFreshは使えなくなりますか?

すぐには使えなくなりません。Denoランタイムは発表から1年間、月次の保守リリースが続き、その後もオープンソースとして残ります。ただしDeno Deployは6か月後に終了するので、デプロイ先は移す必要があります。FreshはDeno社から独立しており、Fresh 3はNode.jsでも動く設計です。

Freshはビルドが必要ですか?

Fresh 2では本番前のビルドが必要です。標準のVite構成では、開発はdeno task dev(Vite)で動き、本番前にdeno task buildで_fresh/を作り、deno serve -A _fresh/server.jsで起動します。レガシーのBuilder構成でも、dev.tsのbuilder.build()で本番用のアセットを作ります。既定でビルド不要だったのは1.xです。

Freshで使うPreactとReactの違いは何ですか?

JSXやフックの書き方はほぼ同じで、Preactは本体が3kB(公式表記)と小さい点が違います。React向けライブラリはpreact/compat経由で多くが動きますが、Reactの内部実装に依存するものは動作確認が要ります。

Fresh 3はいつリリースされますか?

正式版の時期は公表されていません。2026年10月8日にnpmの@frsh/freshで3.0.0-alpha.202610031718が公開されています。Vite 8とNitro 3で作り直したアルファで、Fresh 2のAPIとは互換がない部分があります。

関連記事

お気に入りに入れた記事の一覧

一創の公式 SNS

X では毎朝の新着記事と IT ニュースの速報を、YouTube・TikTok・Instagram・LinkedIn・Facebook では記事の解説動画を配信しています。

この記事は以下の記事からリンクされています

資料請求

今日のトレンド記事 直近 24 時間で、いつもより多く読まれている記事

  1. 2026.10.29 テックブログ ソニー生命の不正アクセス:38.5万件の対象確認と窓口、停止中の手続き
  2. 2026.10.31 テックブログ osinaの情報漏洩:約23万人の対象確認とSNS連携の解除、分析ツールへ渡すデータの絞り方
  3. 2026.10.31 テックブログ 松屋の不正アクセス:237万件の対象確認と窓口、漏れたパスワードの守り方
  4. 2026.05.18 テックブログ マネーフォワードで連携できない・失敗するときの対処法|エラー別の原因と再連携のやり方
  5. 2026.10.31 テックブログ 無印良品の情報漏洩:MUJIアプリ最大2,726万件の対象確認となりすましメール対策

RELATED POSTS 関連記事

目次