p4ni.

比較

Astro と Next.js、コンテンツサイトにはどちらか(2026年版)

· 読了まで約15分

目次

「Astro vs Next.js」の記事の多くは、そもそも競合していない2つを比べています。Next.js はフルスタックの React フレームワークで、Astro は React も動かせるコンテンツ優先のサイトフレームワーク。「どちらが優れているか」と訊けば肩をすくめられて終わりますが、「ブログ・ドキュメント・マーケティングサイト・ディレクトリならどちらか」と訊けば、答えはかなり鋭くなります。

先に結論を書きます。Next.js 16 の既定のページは、機能コードを1行も書かないうちに 642 kB の JavaScript を送ります。このページが送るのは 645 バイトです。これは品質の差ではなく、それぞれのフレームワークが「あなたは何を作っているはずだ」と表明している差です。以下では、どう測ったか、その JavaScript が何を買っているのか、そして私なら今でも Next.js に手を伸ばす場面を書きます。

私の立ち位置: 私は Astro テーマを作って売っているので、明らかなバイアスがあります。そのつもりで読んでください。代わりに2つ差し出します。以下の数字にはすべて、それを出すコマンドを添えてあるので手元で検算できます。そして Next.js のほうが正解になる場面の節は、本当は最初に読んでほしい部分です。

既定でどれだけの JavaScript が飛ぶか

執筆時点のバージョンは Astro 7.1(7.0 は 2026年6月22日)と Next.js 16.2(16.0 は2025年10月)。どちらもこの1年でメジャーリリースを挟み、どちらも目に見えて速くなっているので、2024年の記事はもう古いと思ってください。

この種の比較は仕込みがいくらでも効くので、方法について2つ断っておきます。私が比べているのは、機能コードを書く前にそれぞれが手渡してくるものです。完成した2つのアプリケーション同士を戦わせているわけではありません。最初に手渡されるものからは、後になって降りられないからです。そして両側とも既定のスターターを測り、加えて実在のページを1つ並べます。床の高さと、実際に運用しているサイトの着地点の両方が見えるようにするためです。

# Next.js 側 — この後 next.config.ts に output: 'export' を足す
pnpm dlx create-next-app@latest nextbaseline --ts --app --tailwind --eslint --use-pnpm --yes

# Astro 側
pnpm create astro@latest astrobaseline --template minimal --install --no-git --skip-houston --yes

出てきたのは Next.js 16.2.12(React 19.2.4)と Astro 7.1.4。それぞれ pnpm build した結果が次のとおりです。

Astro スターターこのページ(Astro)Next.js スターター
外部 JS ファイル008
送られる JS0645 B(インライン)642 kB
gzip 後0約 0.4 kB190 kB
その JS の中身テーマ切替React ランタイム、ルーター、プリフェッチ

計測は2026年7月28日、ビルド出力に対して行いました。dev モードの数字は使っていません。gzip の数字はチャンクごとの gzip -9 で、実際に配信される形に合わせています。

数えていないものが3つあり、どれも私の主張には不利に働きます。Next.js のエクスポートには約 8 kB のインラインスクリプト(RSC ペイロード)も乗っていること。このページの 645 バイトは HTML 文書の一部としてまとめて圧縮されるので、単体で 0.4 kB という比べ方には甘さがあること。そしてこのページのアナリティクスタグ、Google の gtag と 293 バイトのインライン初期化も、645 の外にあること。最後のは私が自分で足したもので、フレームワークの責任ではありません。とはいえ回線に乗っているのは変わりません。

文脈から切り離して引用されがちな数字なので、注釈をひとつ。この 642 kB は肥大でも設定ミスでもありません。React 19.2 と App Router のクライアントルーター、そしてプリフェッチの機構で、いずれもあなたが何か書く前に届きます。アプリケーションを作るための入場料です。そしてこのページの 645 バイトも、React のアイランドを1つ載せた瞬間に跳ね上がります。

つまり品質の差ではない。それぞれが何を作らせるつもりでいるか、その想定の差です。

差の出どころは、アイランドか React ランタイムか

Astro はコンポーネントをビルド時に HTML へ描き切り、明示的に頼まない限り JavaScript を一切送りません。これがアイランドのモデルで、オプトインはディレクティブ1つです。

---
import PostHeader from '../components/PostHeader.astro';
import SearchBox from '../components/SearchBox.jsx';
---

<article>
  <!-- JS ゼロ。HTML に描かれ、ビルドの時点で消える -->
  <PostHeader title={post.data.title} />

  <!-- こちらはハイドレートする。React は届くが、このコンポーネントの分だけ -->
  <SearchBox client:visible />
</article>

既定ではすべてが静的で、インタラクティブ性は宣言して初めて現れる例外という扱いです。client:visible を書けば、コンポーネントが画面に入るまで JavaScript を保留することもできます。

Next.js は逆向きです。React Server Components を使えばコンポーネントはサーバー側で描けますが、App Router はページごとに React ランタイムとクライアントルーターを起動します。ナビゲーション、プリフェッチ、Suspense 境界、Server Actions を成り立たせるためです。完全に静的なページであっても、それは「まだ動的な部分がないだけの React アプリケーション」です。

どちらの既定も間違ってはいません。違う問いへの答えです。

誰もベンチマークしない部分、コンテンツをどう入れるか

バンドルサイズはみんなが戦わせたがる論点です。コンテンツサイトで実際に時間を食うのは、そもそもコンテンツをサイトに入れる経路のほうです。

Astro はこれをフレームワークの中で、content collections として答えています。スキーマを一度定義すれば、すべてのファイルがビルド時に検証されます。

// src/content.config.ts
const blog = defineCollection({
  loader: glob({ base: './src/content/blog', pattern: '**/*.{md,mdx}' }),
  schema: z.object({
    title: z.string(),
    pubDate: z.coerce.date(),
    category: z.enum(['tutorial', 'comparison', 'build-in-public']),
    draft: z.boolean().default(false),
  }),
});

pubDate の打ち間違い、title の欠落、一覧にないカテゴリ。どれも公開されずビルドで落ちますし、getCollection('blog') は完全に型の付いた形で返ってきます。この型付き frontmatter があるおかげで、正しい JSON-LD を出す作業はフィールドの写像で済みます。文字列テンプレートを手で組み立てる必要はありません。

Next.js にフレームワーク組み込みの相当物はありません。MDX は自分で配線し、型安全の層はその上に足すので、サードパーティの依存を選ぶ話になります。多くの人が使っていた Contentlayer は2023年6月からリリースが止まっていて、いまはコミュニティのフォーク(contentlayer2)と後継格の Content Collections が生きた選択肢です。どれも十分に実現できますが、組み立てと保守は自分の担当になります。

バンドルサイズの差と同じ構図が、ひとつ上の階層でも繰り返されている、ということです。Astro はコンテンツを主役の対象と見なし、Next.js はたまたま描画しているデータと見なします。

その JavaScript が Next.js 側で買っているもの

払った分の見返りも本物です。Next.js 16 は、率直に言って強いリリースです。

  • Cache Components"use cache" ディレクティブと Partial Prerendering。1つのルートが静的なシェルを即座に返し、パーソナライズされた部分をストリームで流し込めます。キャッシュは Next.js 13〜14 で全員を混乱させた暗黙の挙動をやめ、完全なオプトインになりました。有効化は next.config.tscacheComponents: true
  • Server Actions — API 層を手書きせずにミューテーションを書けます
  • proxy.tsmiddleware.ts の改名版。Node.js ランタイムで動き、旧ファイル名は非推奨に。認証ゲート、リライト、地域別ルーティングのためのリクエスト差し込み
  • ISR とオンデマンド再検証revalidateTag() と、read-your-writes のために増えた updateTag()
  • React エコシステムがそのまま — あらゆるコンポーネントライブラリ、あらゆるフック、統合レイヤーなし

ログイン後のダッシュボード、ユーザーごとの描画、データベースに書き込むフォームが要るなら、その 190 kB はちゃんと何かを買っています。Astro なら同等品を自分で組み上げることになります。

落とし穴は、静的エクスポートにするとほとんど返上すること

コンテンツサイトの議論はたいていここで決着します。Next.js を静的エクスポート、つまりブログを CDN に置くときに使う output: 'export' でデプロイすると、実行時にサーバーが存在しないので、さきほどの一覧の大半も一緒に消えます。Next.js のドキュメントによれば、こうなります。

  • proxy.ts / middleware なし
  • Server Actions なし
  • ISR とオンデマンド再検証なし
  • next.config.tsredirects / rewrites / headers なし。ホスティング側で面倒を見ることになります
  • 動的ルートはすべて generateStaticParams() が必須で、dynamicParamsfalse のまま。未指定なら問題ありませんが、export const dynamicParams = true と書くとビルドが落ちます
  • 画像最適化の組み込みなし(unoptimized: true かカスタムローダーが要ります)

190 kB は残り、それを払う理由のほうが消えます。

当然の反論は「静的エクスポートを使わなければいい」でしょう。サーバーランタイム込みでデプロイすれば、Vercel なら既定の経路ですし、この規模なら無料で、ISR も Server Actions も画像最適化も手元に残ります。正当な選択ですし、すでにその上に乗っているなら私が降ろそうとする理由はありません。

それでも変わらないのがクライアント側です。サーバーで描こうが描くまいが、ブラウザは訪問のたびに、ページが操作可能になる前に React ランタイムと App Router を起動します。ダッシュボードなら、そのコストは長いセッション全体に薄まっていきます。検索から一度だけ開かれ、ミドルレンジの Android で読まれるブログ記事なら、満額を払って何も返ってきません。ここが本当のトレードオフです。「Next.js が遅い」ではなく、「一度読まれて閉じられる文書のために、アプリケーションフレームワークの起動コストを払っている」。

Next.js のほうが正解になる場面

できるだけ率直に並べます。

  • 画面がアプリの形をしている。 ほとんどの画面がインタラクティブなら、たとえばビルダーやエディター、コンポーネントをまたいで状態を持つダッシュボードなら、アイランドだらけになります。そしてアイランド同士は状態を共有しにくい。この密度になると Next.js のほうが素直な設計です。Astro はここで勝とうとしていません
  • クライアントサイドルーティング。 Astro のナビゲーションは既定でフルページロードです。<ClientRouter /> でクライアントルーティングに入れますし、transition:persist はナビゲーションをまたいでアイランドの状態を保てるので、以前より差は縮まりました。それでも Next.js のルーターは標準でより多くを引き受けますし、SPA 寄りのパターンは向こうのほうがはるかに踏み固められています
  • 認証で囲うコンテンツ。 Astro のサーバー出力とアダプターでもできますが、Next.js のほうが道が舗装されていて、書かれた記事の量も桁違いです
  • チームの慣れ。 React のチームは初日から Next.js のほうが速く出せます。.astro ファイルは簡単で、ほとんど HTML ですが、それでも覚えることが1つ増えます

正直な中間解もあります。Astro は React・Vue・Svelte・Solid・Preact のコンポーネントを1行の公式インテグレーションで描けるので、「うちは React の会社なので」は失格理由になりません。インタラクティブな部品を React で書き、ページを .astro で書けばいいだけです。

ビルド速度はもう決め手にならない

この1年、両者ともここに手を入れました。Astro 7 はコンパイラと Markdown パイプラインを Rust で書き直し、Rolldown を積んだ Vite 8 へ移って、公表値で 15〜61% の改善。developers.cloudflare.com(8,431ページ)は 386.9秒から 261.9秒になっています。対する Next.js 16 は Turbopack を dev と本番の既定バンドラーにし、本番ビルドが2〜5倍速いと謳っています。

どちらも十分に速く、これで何かを決めるべきではありません。このサイトは35ページを13秒ほどでビルドしますが、その約8割は記事ごとに Satori が OG 画像を生成している時間で、Astro 自身の取り分は数秒です。

もっとも、Astro 7 が変えたのはビルドの速さだけではありません。同じリリースから AI コーディングエージェントを検出すると astro dev をバックグラウンドに回すようになり、私のマシンでは開発サーバーが26時間動きっぱなしになっていました。

あなたのサイトはどちらか

サイトが…選ぶのは
ブログ、ドキュメント、マーケティングサイト、変更履歴Astro
ディレクトリやカタログ。閲覧中心でほぼ読むだけAstro
インタラクティブな部品がいくつか載るコンテンツサイトAstro(アイランド)
コンテンツとログイン領域が同じドメインに同居Next.js、または Astro にサーバーアダプター
ダッシュボード、エディター、アプリの形をしたものNext.js
チームが React 育ちで、締切が金曜Next.js

実務でよく効く近道が2つあります。

典型的なページでインタラクティブなコンポーネントを数える。 0〜3個なら Astro で楽勝。互いに会話する12個なら Next.js です。

実行時にサーバーが要るかを自問する。 正直な答えが「要らない」なら、その答えをそのまま形にできるのが Astro です。出てくるのは静的ホスティングならどこにでも置けるファイルの集まりです。このサイトは Cloudflare Workers の静的アセットに置いていて、デプロイ工程は astro build && wrangler deploy で終わりです。

結局のところ

コンテンツが商品なら Astro、アプリケーションが商品なら Next.js。645 B 対 642 kB は、どちらが優秀かの点数ではありません。2つのフレームワークがそれぞれ「あなたはこれを作るはずだ」と決めてかかっている、その差です。その想定は知っておいて損がありません。

面白くなるのは、コンテンツとして始まってアプリケーションへ育っていくプロジェクトです。ディレクトリサイトがいちばん分かりやすい例で、閲覧は純粋なコンテンツですが、投稿・検索・管理画面はアプリケーションの仕事になります。

これは両方 Astro で賄えます。静的なページに、動的なルートのためのサーバーランタイムを足す形で、Almanac が Cloudflare Workers と D1 の上でそう動いています。このスタックをゼロから組む手順も書きましたし、自作しないなら使う価値のあるディレクトリテーマも比べてあります。