メインコンテンツへスキップ
Code & Craft
Web制作 約9分で読めます

Astro Prerenderで動的ルートを完全静的化する方法|SSG+動的パスでSEO最大化【2026年4月最新】

Astro 4.0以降のprerender機能で動的ルート([slug])を完全静的化し、SEO評価とパフォーマンスを両立する実装ガイド。getStaticPathsとの組み合わせを実例付きで解説。

Astroで動的ルート([slug].astro)を使うとき、「静的サイトとして生成したいのにビルド時に404エラーが出る」「動的ルートのSEOが不安」という悩みを抱えていませんか?

Astro 4.0以降、prerender機能とgetStaticPathsを組み合わせることで、動的ルートを完全に静的HTML化できるようになりました。これにより、ブログ記事やプロダクトページなど、URLパターンは動的だがコンテンツは事前に確定している場合に、完全な静的サイトとしてのSEO評価とパフォーマンスを実現できます。

この記事では、Astroの動的ルート静的化の仕組み、実装手順、ハマりやすい落とし穴までを、実際のコード例とともに解説します。

Astro Prerenderとは?動的ルートを静的化する仕組み

Astro 4.0(2023年12月リリース)以降、**export const prerender = true**というフラグがページ単位で使えるようになりました。これにより、ハイブリッドレンダリング構成(output: 'server' または output: 'hybrid')の中で、特定のページだけを静的生成(SSG)できます。

しかし、多くの開発者が見落としているのが、完全静的サイト(output: 'static')でも動的ルートには明示的な設定が必要という点です。

動的ルートの静的化に必要な2つの要素

flowchart LR
    A["動的ルートファイル<br/>[slug].astro"] --> B["getStaticPaths()"]
    B --> C["全URLパスを返す"]
    C --> D["ビルド時に各HTMLを生成"]
    D --> E["静的サイトとしてデプロイ"]
    
    style A fill:#e1f5ff
    style E fill:#d4edda
  1. getStaticPaths()関数:ビルド時にどのパス(slug)を生成するか指定
  2. propsを通じたデータ注入:各パスに対応するコンテンツをpropsとして渡す

この2つを正しく実装することで、/blog/article-1/blog/article-2 のような動的パスがビルド時に個別の静的HTMLファイルとして生成されます。

実装手順:ブログ記事の動的ルートを完全静的化する

Step 1: プロジェクト構成の準備

src/
├── pages/
│   └── blog/
│       └── [slug].astro  ← 動的ルート
├── content/
│   └── blog/
│       ├── article-1.md
│       ├── article-2.md
│       └── article-3.md
└── astro.config.mjs

Step 2: Content Collectionsの設定

Astro 4.xでは、Content Collectionsを使ってマークダウンファイルを管理するのがベストプラクティスです。

// src/content/config.ts
import { defineCollection, z } from 'astro:content';

const blogCollection = defineCollection({
  type: 'content',
  schema: z.object({
    title: z.string(),
    description: z.string(),
    publishedAt: z.date(),
    tags: z.array(z.string()),
  }),
});

export const collections = {
  blog: blogCollection,
};

Step 3: 動的ルートでgetStaticPathsを実装

---
// src/pages/blog/[slug].astro
import { getCollection } from 'astro:content';
import type { GetStaticPaths } from 'astro';

// ビルド時に全記事のパスを生成
export const getStaticPaths = (async () => {
  const blogEntries = await getCollection('blog');
  
  return blogEntries.map(entry => ({
    params: { slug: entry.slug },
    props: { entry },
  }));
}) satisfies GetStaticPaths;

// propsから記事データを受け取る
const { entry } = Astro.props;
const { Content } = await entry.render();
---

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>{entry.data.title}</title>
  <meta name="description" content={entry.data.description}>
  <link rel="canonical" href={`https://example.com/blog/${entry.slug}`}>
</head>
<body>
  <article>
    <h1>{entry.data.title}</h1>
    <time datetime={entry.data.publishedAt.toISOString()}>
      {entry.data.publishedAt.toLocaleDateString('ja-JP')}
    </time>
    <Content />
  </article>
</body>
</html>

Step 4: ビルド設定の確認

// astro.config.mjs
import { defineConfig } from 'astro/config';

export default defineConfig({
  output: 'static', // 完全静的サイトとして生成
  site: 'https://example.com', // canonicalタグ・サイトマップ用
});

ビルド結果の確認とSEOへの影響

静的HTMLの生成確認

ビルドを実行すると、以下のように各slugに対応するHTMLファイルが生成されます。

npm run build
dist/
└── blog/
    ├── article-1/
    │   └── index.html
    ├── article-2/
    │   └── index.html
    └── article-3/
    │   └── index.html

これにより、/blog/article-1 へのアクセスは静的HTMLとして即座に配信され、以下のSEO上の利点が得られます。

SEOパフォーマンスの改善指標

指標SSR/動的生成SSG(prerender)改善効果
TTFB200-500ms10-50ms80-90%削減
FCP1.5-3.0s0.5-1.0s60-70%短縮
クローラー処理時間変動あり安定して高速インデックス効率向上
キャッシュ効率低いCDNで永続化可能配信コスト削減

注: 上記の数値は一般的な実測値の範囲であり、実際の環境・コンテンツによって変動します

よくあるエラーと解決策

エラー1: getStaticPaths() が定義されていない

Error: getStaticPaths() function is required for dynamic routes.

原因: 動的ルート([slug].astro)でgetStaticPathsを実装していない

解決策: 上記Step 3のコードを参考に、必ずgetStaticPathsを実装する

エラー2: 一部のslugでビルドが失敗する

Error: [slug] does not match any static paths

原因: Content Collectionsのファイル名とslugが一致していない、またはフロントマターが不正

解決策:

  • ファイル名を確認(例: article-1.md → slug: article-1
  • schema検証エラーがないかログを確認
  • getCollection('blog', (entry) => !entry.data.draft) のようにフィルタリングしている場合、意図しない除外がないか確認

エラー3: propsがundefinedになる

const { entry } = Astro.props; // entry が undefined

原因: getStaticPathsでpropsを返していない

解決策:

return blogEntries.map(entry => ({
  params: { slug: entry.slug },
  props: { entry }, // ← これを必ず含める
}));

外部APIからデータを取得して静的化する

Content Collections以外に、外部API(HeadlessCMS、microCMS、Strapi等)からデータを取得して静的化することも可能です。

---
// src/pages/products/[id].astro
import type { GetStaticPaths } from 'astro';

export const getStaticPaths = (async () => {
  // 外部APIから商品一覧を取得
  const response = await fetch('https://api.example.com/products');
  const products = await response.json();
  
  return products.map((product: any) => ({
    params: { id: product.id.toString() },
    props: { product },
  }));
}) satisfies GetStaticPaths;

const { product } = Astro.props;
---

<h1>{product.name}</h1>
<p>{product.description}</p>
<meta name="description" content={product.description}>

ビルド時の注意点

  • APIレート制限に注意: 数百〜数千のパスを生成する場合、API呼び出しが制限に引っかかる可能性がある
  • 環境変数の管理: APIキーは .env ファイルで管理し、.gitignore に追加
  • エラーハンドリング: API障害時にビルドが止まらないよう、フォールバック処理を実装
export const getStaticPaths = (async () => {
  try {
    const response = await fetch('https://api.example.com/products');
    if (!response.ok) throw new Error('API fetch failed');
    const products = await response.json();
    return products.map(/* ... */);
  } catch (error) {
    console.error('Failed to fetch products:', error);
    return []; // 空配列を返してビルドを継続
  }
}) satisfies GetStaticPaths;

ハイブリッドレンダリングとの使い分け

Astro 4.5(2024年6月リリース)以降、output: 'hybrid' モードが強化され、動的ルートと静的ルートを同一プロジェクトで混在させやすくなりました。

graph TD
    A["astro.config.mjs<br/>output: 'hybrid'"] --> B["デフォルト: SSR"]
    B --> C["pages/blog/[slug].astro<br/>export const prerender = true"]
    B --> D["pages/api/search.ts<br/>prerenderなし(動的)"]
    C --> E["静的HTML生成"]
    D --> F["リクエスト時に実行"]
    
    style C fill:#d4edda
    style D fill:#fff3cd

使い分けの基準

ユースケース推奨モード理由
ブログ記事、製品ページprerender: trueコンテンツが事前確定、SEO重視
検索API、フォーム送信SSR(prerenderなし)リクエストごとに処理が変わる
ユーザーダッシュボードSSR認証・個別データ表示が必要
ランディングページprerender: true高速表示、CDNキャッシュ活用

まとめ

  • Astroの動的ルート静的化には getStaticPaths() が必須。これがないとビルドエラーになる
  • Content Collectionsを使えば、マークダウンファイルから自動的にパスを生成でき、型安全性も確保できる
  • 外部APIからデータを取得する場合も、ビルド時に全パスを生成することで完全静的化が可能
  • SEO上の最大の利点はTTFBの劇的な短縮(200-500ms → 10-50ms)とクローラーへの最適化
  • ハイブリッドレンダリング(output: 'hybrid')を使えば、静的ページと動的APIを同一プロジェクトで管理できる
  • エラーハンドリングとAPI制限を考慮し、大規模サイトでは段階的な生成戦略を検討する

動的ルートの静的化は、AstroのパフォーマンスとSEOを最大限に活かすための必須テクニックです。Content Collectionsとの組み合わせで、保守性の高い静的サイト構築を実現しましょう。

参考リンク

#Astro #SSG #SEO #パフォーマンス最適化 #動的ルート
シェア: