AstroのSEO

AstroはSEOに強いフレームワークの1つです。デフォルトではページを静的HTMLにプリレンダリングし、指定した場所だけJSを送るため、強いCore Web Vitalsが期待できます。ただしデフォルトは保証ではなく、metaタグ、サイトマップ、canonicalは自動生成されません。私が自分のAstroサイトをどう運用しているか、適切なアーキテクチャをどう作るかを解説します。

初回公開:2026年6月26日 · 最終更新:2026年8月8日 · Advanced
言語

AstroがSEOに強いフレームワークの選択肢である理由は、デフォルトで静的HTMLへプリレンダリングするためです。最初のクロールで生HTMLにコンテンツがあり、そのルートではレンダリングキューを待ちません。Islandsはclientディレクティブを付けたコンポーネントだけをハイドレーションするため、ページの大部分は専用のハイドレーションJSなしで配信されます(Astroは別の場所でページスクリプトやルーターJSを追加できます)。ただし、これだけでクロール可能性、インデックス登録、順位は保証されないため、デプロイ済みルートを確認します。Astroサイトは強いCore Web Vitalsの数字も出します。注意点は、きれいなHTMLを生成してもmetaタグ、canonical、サイトマップ、構造化データは書かないことです。これらは明示的なビルド手順であり、サイトマップの検出対象は静的生成ルートなので、ランタイム専用URLには明示的な処理が必要です。アダプターが必要なServer IslandsとView Transitionsは、クローラーが実際に取得するものを理解すればSEOに安全です。私はpatrickstox.comをAstroで運用しており、これが実際に使っているスタックです。

TL;DR — AstroはSEO向けにアーキテクチャがよく整っています。デフォルトではページとエンドポイントが静的HTMLにプリレンダリングされるため、そのコンテンツについてレンダリングキューの波を待つ必要がありません。ただしこれはデフォルトであって、すべてのルートに共通する保証ではありません。静的/サーバーHTMLだけで本番URLのクロール可能性、インデックス登録、順位、Core Web Vitalsが証明されるわけでもありません。Islandsアーキテクチャはclient:*ディレクティブを付けたコンポーネントだけをハイドレーションします。それ以外は専用のハイドレーションJSなしでHTMLを送りますが、ページスクリプト、他のIsland、ルーター拡張がページの別の場所にJavaScriptを追加することはあります。Astroはmetaタグ、canonical、サイトマップ、構造化データを自動生成しません。Content CollectionsとZodで検証しながら、明示的に接続します。アダプターが必要なServer Islandsは初期ドキュメントにフォールバックコンテンツ付きの静的シェルを返し、遅延コンテンツを後から独立して取得します。クローラーが実際に何を取得するかを確認してください。View Transitionsはhistory.pushStateを使うためSEOに安全で、Googleは基礎にあるMPAページを通常どおりクロールします。私はpatrickstox.comをAstroで運用しており、以下はローカル開発だけでなくデプロイ済みサイトで検証して実際に使っている機能です。

Evidence for this claim Astro prerenders pages as static HTML by default and only sends client JavaScript for explicitly hydrated components. Scope: Astro default static output and islands architecture. Confidence: high · Verified: Astro: Why Astro

AstroがJavaScriptレンダリングの問題を完全に回避する理由

JavaScript SEOが難しい理由は、2回目の波にあります。Googleはまず生HTMLを取得し、その後ヘッドレスChromiumでレンダリングするためにページをキューへ入れます。このキューがリスクです。Google自身のドキュメントにはこうあります。“Googlebot queues all pages with a 200 HTTP status code for rendering unless a robots meta tag tells Google not to index the page. The page may stay on this queue for a few seconds, but it can take longer than that.” (翻訳)(robots metaタグがページをインデックス登録しないようGoogleに伝えない限り、GooglebotはHTTPステータスコード200のすべてのページをレンダリング用にキューへ入れます。ページは数秒このキューに留まることがありますが、それより長くなる場合もあります。)クライアントレンダリングのSPAでは、そのレンダリング波が動くまでコンテンツが存在しません。

Astroのデフォルト出力モードはstaticです。ページとエンドポイントはビルド時に完全なHTMLファイルへプリレンダリングされます。したがって、そのデフォルトで動くルートでは、生HTML自体がレンダリング済みページです。 Evidence for this claim Astro uses static output and prerenders routes at build time by default. Scope: Astro default output mode; routes can opt out of prerendering. Confidence: high · Verified: Astro: On-demand rendering 実行するものが残っていないため、そのルートで2回目の波を待つ必要はありません。Googlebotは最初の取得で完全なコンテンツを見ます。Yoast創業者のJoost de Valkの言葉では、“From an SEO perspective, static HTML on a CDN is a better starting point than most CMSes will ever give you.” (翻訳)(SEOの観点では、CDN上の静的HTMLは、ほとんどのCMSが提供できるものよりも優れた出発点です。)

ただし、これはデフォルトです。すべてのルートに共通する性質ではありません。output: 'server'を設定すると、デフォルトはオンデマンドレンダリングへ切り替わります(詳しくは後述)。静的デフォルトのプロジェクトでも、アダプターを使えば個々のルートがexport const prerender = falseでオプトアウトできます。アーキテクチャだけで何かが保証されるわけではありません。静的/サーバーHTML、Island、アダプターだけでは、クロール可能性、インデックス登録、順位、Core Web Vitalsは保証されません。デプロイされたルートと個々のクローラーに依存するため、フレームワークが処理すると決めつけず検証します。

これは、まったくレンダリングできないクローラーにも役立ちます。Googleは*“not all bots can run JavaScript”* (翻訳)(すべてのボットがJavaScriptを実行できるわけではありません。)と明確に述べています。これは2026年の現実で、ほとんどのAIクローラーや多くのサードパーティーツールに当てはまります。AstroのHTML優先出力は、実際にプリレンダリングされた場所ではGooglebotだけでなく、すべてのクローラーが読めます。(これはSEO for a headless CMSで述べているのと同じ点です。レンダリングモードが製品そのものです。)

Islandsアーキテクチャ:求めた場所だけJSを使う

AstroはコンポーネントをHTMLへレンダリングし、言葉どおり「just HTML & CSS, stripping out all client-side JavaScript automatically」を送ります。インタラクティブ性はオプトインです。client:*ディレクティブ(client:loadclient:idleclient:visible)をコンポーネントに付けると、そのIslandだけがJavaScriptでハイドレーションされます。それ以外は静的HTMLのままです。 Evidence for this claim Astro client directives selectively hydrate interactive islands while other components remain static HTML. Scope: Astro islands and client directives. Confidence: high · Verified: Astro: Islands

SEOにとっては理想に近い構成です。Googlebotがインデックス登録する必要があるコンテンツはプレーンHTMLで、インタラクティブなウィジェットがページを重くしません。client:visibleは特に便利です。ページ下部のコンポーネントは、スクロールして見えるまでハイドレーションを始めないため、LCPをブロックしません。この概念はPreactの作者Jason Millerが提唱したもので、“rendering HTML pages on the server, and inject[ing] placeholders or slots around highly dynamic regions” (翻訳)(サーバーでHTMLページをレンダリングし、動的な領域の周囲にプレースホルダーまたはスロットを挿入すること)と説明しました。

競合の説明が混同しがちな、正確に区別すべき2つの注意点があります。

  • client:onlyは別物です。 client:loadclient:idleclient:visibleと違い、client:onlyコンポーネントはサーバーレンダリングを完全に省略し、サーバー上ではHTMLをまったく生成しません。client:onlyの内部だけに置いたインデックス登録対象のコンテンツは、Googlebotが取得するドキュメントに存在せず、ブラウザーがハイドレーションした後にだけ存在します。主要コンテンツを置かないでください。
  • これは選択的ハイドレーションであり、レジューム可能性ではありません。 Astroはブラウザーで各Islandのクライアントコードを最初から再実行します。Qwikのようなレジューム可能性モデルがサーバーでシリアライズした実行状態を再開する仕組みではありません。記事では混同されますが、同じメカニズムではありません。
Evidence for this claim A client:only component skips server rendering, so indexable content placed only inside it cannot be assumed to exist in the initial page HTML. Scope: client and server islands Confidence: high · Verified: Template directives reference

ハイドレーションされないコンポーネントだけで、ページ上のJavaScriptの全体像が決まるわけでもありません。「Zero JS」とはclient:*ディレクティブのない1つのコンポーネントを説明する言葉です。Astroはページレベルの<script>タグ、View Transitionsルーター、ページ上の別のIslandを送ることがあります。ページ全体についての一括した主張ではなく、コンポーネント/ルートごとに何が送られるかを説明してください。

Astroが自動ではしないこと

Astroは意味のあるきれいなHTMLを生成しますが、SEOに関してはそれだけです。メタデータ、canonical、サイトマップ、構造化データは初期状態ではありません。「Astroは自動的にSEO最適化される」という神話は、そのまま神話です。自分で設定するものは次のとおりです。

  • Metaタグ(title、description、Open Graph、Twitter)
  • Canonical URL
  • サイトマップ(公式インテグレーション経由)
  • 構造化データ/JSON-LD
  • robots.txt

Astroは私が使った中で最良の基盤ですが、基盤であって完成した家ではありません。

サイトマップ:@astrojs/sitemap

npx astro add sitemapでインストールします。静的に生成されたルートをクロールし、ビルド時にsitemap-index.xmlと分割されたsitemap-0.xmlファイルを出力します。2つの点でつまずく人がいます。

Evidence for this claim Astro's official sitemap integration generates sitemap files from statically generated routes. Scope: Astro @astrojs/sitemap integration. Confidence: high · Verified: Astro: Sitemap integration
  • astro.config.mjssite:を設定する必要があります。 設定しないと、インテグレーションは何も生成せずに静かに終わります。「サイトマップはどこ?」の原因として最も多いものです。
  • robots.txtにサイトマップの行を自分で追加する必要があります。 Astroは行を追加しません。

制御するには、filter()でルート(プレビュー/下書きページなど、このサイトでまさに使っているもの)を除外し、serialize()lastmodchangefreqpriorityを設定し、i18nオプションでサイトマップにhreflangエントリを出力します。これは現在の@astrojs/sitemapドキュメントの仕様です。古いリリースを使っている場合はインストール済みのバージョンで確認してください。インテグレーションの動作は過去にメジャーバージョン間で変わっています。

人がつまずく範囲: インテグレーションの検出対象は静的に生成されたルートです。URLがランタイムにしか存在しない場合、サーバーレンダリング(output: 'server')のルートやビルド時ではなくオンデマンドで生成されるルートがサイトマップに入ると決めつけないでください。customPagesで明示的に追加し、ビルド後にsitemap-index.xmlを実際に開いて存在を確認します。ビルド時の静的ルートでないものについて、「インテグレーションが処理する」と信じるだけでは不十分です。

Metaタグとcanonical:BaseLayoutパターン

Astroには特別な<Head>コンポーネントがありません。.astroファイルで<head>を直接制御します。標準的なパターン、そして私が使っている方法は、titledescriptioncanonicalURLをpropsとして受け取りheadを書き出す単一のBaseLayout.astroです。すべてのページでcanonicalを明示し、og:urlと一致させます。ライブラリは不要ですが、コミュニティのastro-seoパッケージ(npm)は、title/description/OG/Twitter/canonicalを1つのコンポーネントで包む便利なラッパーです。

Content CollectionsをSEOの安全網にする

これはAstroの過小評価されているSEO機能です。Content Collectionsは、Markdown/MDX/JSON向けの型安全なコンテンツレイヤーで、Zodスキーマ検証を備えています。つまり、titledescription必須フィールドにでき、ページにどちらかがなければビルドが失敗します。titleのないページを誤って公開できません。getCollection()getEntry()などのクエリ関数はビルド時に静的ページを生成するため、デプロイ時の出力はプレーンHTMLです。MDXが生のMarkdownを真実のソースとして保持するので、これらのファイルはAIクローラーやllms.txt形式のパターンにとってもきれいなソースコンテンツです。このサイト自体も、Zodでfrontmatterを検証するContent Collectionsで構築しています。

astro:assets:画像を正しく扱う(1つの落とし穴)

<Image />コンポーネントは自動的にWebPへ変換し、「Cumulative Layout Shift(CLS)を避ける」ために寸法を推測し、デフォルトでloading="lazy"を設定し、altを必須にします。altがないとコンパイルエラーになります。<Picture />はAVIF/WebP/フォールバックの<source>要素でこれを拡張します。

落とし穴は、デフォルトのloading="lazy"LCP画像(通常はヒーロー画像)には不適切なことです。最も重要な画像を遅延読み込みすると、その画像の遅延が起きます。ファーストビューの画像ではloading="eager"fetchpriority="high"で上書きします。リモート画像には明示的なwidthheightが必要です。

Server Islands:クローラーが実際に見るもの

Server Islands(Astro 4,12以降)は、競合のガイドが最もよく間違える機能です。server:deferを使うと、コンポーネントはメインページとは独立してサーバー上でレンダリングされます。静的シェルはすぐに配信され、Astroのドキュメントによれば、“Your page will be rendered immediately with any specified fallback content as a placeholder. Then, the component’s own contents are fetched on the client and displayed when available.” (翻訳)(指定したフォールバックコンテンツをプレースホルダーとして、ページはすぐにレンダリングされます。その後、コンポーネント自身の内容がクライアントで取得され、利用可能になった時点で表示されます。)となります。

正確に説明すべき点が2つあります。第一に、Server Islandsにはアダプターが必要です。純粋な静的ビルドが単独で生成するものではなく、オンデマンド機能です。第二に、流れはこうです。初期ドキュメントには設定したフォールバックコンテンツが含まれ、Islandの実コンテンツはページ読み込み後に独自のエンドポイントから別の独立したリクエストで取得されます。これは最初のドキュメントに含まれる内容の明確な下限です。自分のデプロイ済みURLを直接テストせずに、各クローラーが次に何をするかを一般化しないでください。

SEO上の影響は具体的です。最初の取得でクローラーが読む静的HTMLに含まれるのは、遅延Islandのコンテンツではなくフォールバックコンテンツです。 これはServer Islandsの目的である、キャッシュやインデックス登録を避けるべき個人化・セッション固有の情報(ログイン状態、カート数、レコメンド)には最適です。主要なインデックス登録対象コンテンツには不適切です。順位が必要なものはメインのAstroテンプレートに置き、Server Islandsには周囲の動的な部分だけを任せてください。

出力モード:staticとserver、ルートごとの上書き

Astroのデフォルト出力モードはstaticです。ページとエンドポイントはビルド時にHTMLへプリレンダリングされます。astro.config.mjsoutput: 'server'を設定するとデフォルトはオンデマンドレンダリングになり、アダプターを使ってリクエストごとにページを描画します。Server Islandsでは足りない認証、リアルタイムデータ、個人化に役立ちます。どちらのモードでも、ルートごとにデフォルトを上書きできます。静的デフォルトのプロジェクトではexport const prerender = falseでオンデマンドに、サーバーデフォルトのプロジェクトではexport const prerender = trueでビルド時のプリレンダリングに戻せます。「サイトは静的」「サイトはSSR」という説明がすべてのルートに当てはまることはほとんどありません。トップレベルの設定だけでなく、ルートごとの設定を確認します。

Evidence for this claim Astro uses static output and prerenders routes at build time by default. Scope: Astro default output mode; routes can opt out of prerendering. Confidence: high · Verified: Astro: On-demand rendering

純粋なSEOの観点では、プリレンダリングHTMLとオンデマンドHTMLは同等です。実際にルートが完全なマークアップ付きで200を返すことを確認できれば、どちらもクローラーの最初のリクエストに完全なHTMLを返します。オンデマンドのルートはHTMLをストリーミングでき、遅いデータやネットワーク状況で後続チャンクが遅れることがあるため、ストリーミングレスポンスはすべてのコンテンツが届いた証明にはなりません。確認してください。2つのモードの本当の違いは運用です。プリレンダリングコンテンツは次のビルド(または別途設定したランタイム更新)まで固定され、CDNエッジから直接配信されます。オンデマンドコンテンツは常に最新ですが、本番でアダプターとランタイムが正常であることに依存します。SEOの選択とは考えず、データの新しさと運用で選び、ローカル開発で動いたことから推測せずに、デプロイ済みルートのステータス、リダイレクト、レスポンスヘッダーを検証します。

View Transitions:SPAのように見えてもSEOに安全

Astroの<ClientRouter />(以前の<ViewTransitions />)は、ブラウザーのView Transitions APIとHistory APIを使ってSPAのようなソフトナビゲーションを提供します。重要なのは、history.pushStateで移動することです。これはGoogleがクライアント側ナビゲーションに推奨している方法です。Googleはフラグメントベース(#hash)のURLを「can’t reliably resolve」と警告しています。重要なのは、View Transitionsがブラウザー側の拡張であることです。Googlebotがクロールするときは各URLをリクエストし、通常の完全なHTMLページを取得します。下にあるMPAは変わりません。トランジションが変えるのはブラウザーで人間が見るものだけです。

したがって、View TransitionsがAstroサイトをSPAに変えたり、SEOを壊したりするわけではありません。注意すべき空白は、AstroのView TransitionsドキュメントにSEOのセクションがないことです。そのため「SEOを壊す」という神話が残っているのでしょう。自分のサイトで確認するには、いくつかのURLを直接取得して、それぞれが完全なHTMLを返すことを確認してください。思い込みで済ませず、自分のデプロイを確認します。

よくあるAstro SEOのミス

  1. AstroがSEOを処理してくれると思う。 Astroが処理するのはHTMLです。Meta、canonical、サイトマップ、schemaは自分で設定します。
  2. 設定でsite:を忘れる。 サイトマップが静かに生成されません。
  3. robots.txtにサイトマップを追加しない。 Astroは追加しません。
  4. LCP画像を遅延読み込みする。 ヒーロー画像をeagerfetchpriorityで上書きします。
  5. インデックス登録対象コンテンツをServer Islandに置く。 クローラーが見るのはフォールバックで、そもそもServer Islandsにはアダプターが必要です。
  6. 完璧なLighthouseスコアを追いかけて止まる。 速度は順位シグナルの1つであり、唯一の順位シグナルではありません。速くても空のページは順位が上がらず、コンテンツ、リンク、E-E-A-Tが引き続き大きな役割を果たします。
  7. インデックス登録対象コンテンツをclient:onlyコンポーネントの中だけに置く。 他のclient:*ディレクティブと違って、client:onlyはサーバーレンダリングを完全に省略するため、ブラウザーがハイドレーションするまでそのコンポーネントのHTMLはありません。
  8. 「Astroは静的/高速」を成果の保証として扱う。 静的またはオンデマンドHTML、Island、アダプターは仕組みです。それだけでクロール可能性、インデックス登録、順位、Core Web Vitalsを保証しません。アーキテクチャ図ではなく、デプロイ済みルートを検証してください。

このトピッククラスターでの位置付け

Astroは、JavaScript SEOが提起するレンダリングの問いに対する、具体的で特にSEOに強い答えの1つです。また、headless CMS構成で人気のフロントエンドでもあります。パフォーマンスの側面はウェブパフォーマンスクラスターのCore Web Vitalsに直接つながり、「コンテンツが実際にHTMLにあるか」をテストする習慣はクロールとインデックス登録のクラスターと同じです。

Add an expert note

Pin an expert quote

New person? Create their unclaimed profile at /admin/experts/ → Pin a quote first.