【Astro】サイトマップの作り方|@astrojs/sitemapの設定

【Astro】サイトマップの作り方|@astrojs/sitemapの設定

Astroでブログを公開したけど、サイトマップってどうやって用意すればいいの?

XMLを手で書くのは大変そう…。記事を増やすたびに書き直すのかな?

Astroでサイトを公開したあと、「サイトマップも用意したほうがいいのかな」と気になっていませんか?
WordPressならプラグインで済んでいた部分なので、静的サイトではどうするのか迷いやすいところだと思います。

結論からいうと、Astroなら公式インテグレーションの @astrojs/sitemap を入れるのが手軽です。
ビルドのたびにページの一覧からサイトマップを作ってくれるので、記事を足すたびに手で書き直す必要はありません。

ただし、site の設定を忘れてもエラーにならなかったり、開発サーバーでは生成されなかったりと、気づきにくいポイントもあります。
この記事では、導入から検索エンジンへの伝え方、よく使うオプション、生成されないときの確認までを順番に整理していきます。

この記事でわかること
  • サイトマップの役割と、@astrojs/sitemap の導入手順
  • robots.txt・head・Google Search Console でサイトマップの場所を伝える方法
  • filter・serialize でのページ除外と、changefreq・lastmod の扱い方
  • サイトマップが生成されない・反映されないときの確認ポイント

このブログもAstroと@astrojs/sitemapの組み合わせで動いています。WordPressから移ってきた経緯は別記事にまとめているので、よければあわせてどうぞ。

この記事の前提(2026年9月時点)
  • Astro 7.3系と @astrojs/sitemap 3.7.4(2026年8月31日リリース)を対象にした内容です
  • パッケージマネージャは pnpm で書いていますが、npm・yarn でもコマンドを読み替えれば同じです

公式ドキュメントは @astrojs/sitemap(Astro Docs) にあります。

サイトマップとは?検索エンジンに渡すページURLの一覧

サイトマップは、サイト内にどんなページがあるかを検索エンジンに伝えるためのファイルです。
中身は、ページのURLを並べたXML形式のリストになっています。

検索エンジンは、ページ内のリンクをたどって新しいページを見つけていくのが基本です。
サイトマップはそれとは別に、「このサイトにはこういうURLがあります」とまとめて渡しておくためのもの、というイメージです。

建物でいえば、入口に置いてある館内案内図のようなものです。
案内図がなくても歩き回れば部屋は見つかりますが、あれば全体を把握しやすくなります。

XMLサイトマップ

URLの一覧を決まった書式のXMLで書いたファイルのことです。
1つのURLごとに <url> の中へ <loc>(ページのURL)を入れ、必要に応じて <lastmod>(最終更新日)などを添える形になっています。

注意したいのは、サイトマップはあくまでURLを知らせる手段の1つだということです。
サイトマップに載せたからといって、そのページが検索結果に出ることが約束されるわけではありません。

@astrojs/sitemap でサイトマップを生成する手順

Astroには公式インテグレーションの @astrojs/sitemap があり、ビルドのときにページの一覧からサイトマップを書き出してくれます。
やることは、インテグレーションの追加・site の設定・ビルドでの確認の3つです。

1. インテグレーションを追加する

いちばん手軽なのは、astro add コマンドを使う方法です。

pnpm astro add sitemap

パッケージのインストールと astro.config.mjs への追記をまとめてやってくれます。npm なら npx astro add sitemap です。

手動で入れる場合は、パッケージを追加してから設定ファイルに書き足します。

pnpm add @astrojs/sitemap

設定ファイルでは、sitemap を読み込んで integrations に入れます。

// astro.config.mjs
import { defineConfig } from "astro/config";
import sitemap from "@astrojs/sitemap";

export default defineConfig({
  site: "https://example.com",
  integrations: [sitemap()],
});

integrations の配列に sitemap() を入れるだけで、オプションを何も渡さなくても動きます。

2. site にサイトの公開URLを設定する

上のコードで一緒に書いている site が、このインテグレーションでいちばん大事な設定です。
@astrojs/sitemap は、この値を使ってページの完全なURLを組み立てます。

やっかいなのは、site を書き忘れてもビルドはエラーにならないことです。
代わりに、ビルドのログにこんな警告が出て、サイトマップの生成だけがスキップされます。

The Sitemap integration requires the `site` astro.config option. Skipping.

ビルド自体は成功して見えるので、サイトマップだけ出ていないことに気づきにくいんですよね。
導入したら、ログにこの警告が出ていないか一度見ておくと安心です。

らるじゅらるじゅ

エラーで止まってくれれば一発で気づけるんですが、警告だけで先に進むのがちょっと意地悪なところ。
「sitemapを入れたらsiteも書く」とセットで覚えておくのがいいと思います。

3. ビルドして sitemap-index.xml ができているか確認する

@astrojs/sitemap はビルドが終わったタイミングでサイトマップを書き出します。
つまり astro dev の開発サーバーでは生成されないので、確認はビルドしてから行います。

pnpm build

ビルドが終わると、出力先の dist/ に次の2種類のファイルができます。

ファイル役割
sitemap-index.xml子サイトマップの場所をまとめた目次。検索エンジンにはこちらを伝える
sitemap-0.xml実際のページURLが並んでいる本体

sitemap-index.xml はページのURLを直接持つのではなく、sitemap-0.xml のような子サイトマップを束ねる役割です。
URLの数が上限(既定は1ファイル45,000件)を超えると sitemap-1.xml 以降に分かれ、それも index にまとめて載ります。

見やすく改行すると、sitemap-index.xml の中身はおおよそ次のような形です(example.com の例)。

<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <sitemap>
    <loc>https://example.com/sitemap-0.xml</loc>
  </sitemap>
</sitemapindex>

sitemap-0.xml のほうには、ページごとに <url> と <loc> が並びます。
オプションを指定しない既定の状態では <lastmod> などは付かず、URLだけのシンプルな一覧になります。

このブログも同じ構成で、sitemap-index.xml から sitemap-0.xml を1つだけ参照する形になっています。

サイトマップの場所を検索エンジンに伝える

サイトマップができたら、次はどこにあるのかを知らせておく準備です。
方法は主に3つあり、このブログではそのうち robots.txt と head の2か所に書いています。

robots.txt にサイトマップのURLを書く

robots.txt は、クローラー向けのルールを書いておくファイルです。
ここに Sitemap: の行を足しておくと、サイトマップの場所も一緒に伝えられます。

静的なファイルで置くなら、public/robots.txt を作ってこう書きます。

User-agent: *
Allow: /

Sitemap: https://example.com/sitemap-index.xml

ドメインを直書きしたくない場合は、src/pages/robots.txt.ts というエンドポイントを作り、site の値から組み立てる方法もあります。

// src/pages/robots.txt.ts
import type { APIRoute } from "astro";

const getRobotsTxt = (sitemapURL: URL) => `User-agent: *
Allow: /

Sitemap: ${sitemapURL.href}`;

export const GET: APIRoute = ({ site }) => {
  const sitemapURL = new URL("sitemap-index.xml", site);
  return new Response(getRobotsTxt(sitemapURL));
};

こちらは astro.config.mjs の site を読んで Sitemap: の行を作るので、ドメインを変えたときの書き換え漏れを防げます。
静的ファイルとエンドポイントは、どちらか片方を用意すれば十分です。

もう1つは、ページの <head> にサイトマップへのリンクを入れる方法です。公式ドキュメントでも、この1行を入れておくことが推奨されています。

レイアウトの head に、次のように追加します。

<head>
  <!-- ほかの meta タグなどと並べて置く -->
  <link rel="sitemap" href="/sitemap-index.xml" />
</head>

共通の head をまとめたコンポーネントがあるなら、そこに1行足しておけば全ページに入ります。
このブログでも、head 用のコンポーネントにこの1行を入れています。

Google Search Console にサイトマップを送信する

Googleに対しては、Google Search Console から直接サイトマップを送信することもできます。

Search Consoleで送信する流れ
  • Search Console で対象のサイトを開く
  • 左メニューの「サイトマップ」を開く
  • sitemap-index.xml のURLを入力して送信する

送るのは sitemap-index.xml の1つだけで大丈夫です。
index には子サイトマップの場所が書かれているので、そこから sitemap-0.xml などもたどってもらえます。

なお、送信はあくまで「サイトマップの場所を知らせる」操作です。
送ったページがすべて検索結果に載る、という仕組みではない点は押さえておきましょう。

よく使う設定オプション|filter・serialize・lastmod

@astrojs/sitemap は、sitemap() にオプションを渡して挙動を変えられます。
ここでは出番の多そうな3つを取り上げて、最後に一覧表でまとめます。

filter でサイトマップに載せたくないページを外す

特定のページをサイトマップから外したいときは filter を使います。
関数には各ページの完全なURLの文字列が渡ってくるので、残したいページなら true、外したいページなら false を返します。

たとえば、一覧の2ページ目以降のように、URLの末尾が /2/ /3/ と数字だけになっているページを外すなら、こう書けます。

// astro.config.mjs
import { defineConfig } from "astro/config";
import sitemap from "@astrojs/sitemap";

export default defineConfig({
  site: "https://example.com",
  integrations: [
    sitemap({
      // パスの末尾が「/数字/」のページを除外する
      filter: (page) => !/\/\d+\/$/.test(new URL(page).pathname),
    }),
  ],
});

page は https://example.com/2/ のような完全なURLなので、new URL(page).pathname でパスの部分だけを取り出して判定しています。
末尾にスラッシュが付くURL構成を前提にした書き方で、スラッグが数字だけの記事ページも一緒に外れる点には注意してください。

ちなみに、このブログのサイトマップにもトップの一覧の /2/ /3/ や、カテゴリのページが含まれています。
こうしたページを外すかどうかはサイトの方針次第で、外さないといけないものではありません。

changefreq・priority・lastmod は入れるべき?

@astrojs/sitemap には、changefreq(更新頻度)・priority(優先度)・lastmod(最終更新日)を付けるオプションもあります。
ただ、Google向けに限っていえば、無理に入れなくてよいと思います。

Googleは、サイトマップの作り方を説明した公式ドキュメントで、priority と changefreq の値は無視すると明言しています。

lastmod のほうは、Googleが使う場合があります。
ただし条件つきで、一貫して正確で、確認できる場合に使うとされています。
日付も、ページの主要な内容や構造化データ、リンクが変わったときのものであるべきで、著作権表記を直しただけのような更新は含みません。

ここで気をつけたいのが、@astrojs/sitemap の lastmod オプションの仕様です。
このオプションは日付(Date)を1つ受け取るだけなので、すべてのURLに同じ日付が付きます。

つまり、ビルドした日付を一律に入れると、実際には更新していない記事まで「ビルド日に更新された」ことになってしまいます。
Googleが正確な lastmod を前提にしている以上、意味が薄いうえに、逆効果にもなりえます。

ページごとの本当の更新日を出したい場合は、serialize を使って、URLと記事の更新日を自分で対応付ける必要があります。
記事データの持ち方によって書き方が変わるので、ここでは深入りしません。

このブログも lastmod は出しておらず、オプションを何も指定しない既定のままです。

らるじゅらるじゅ

「とりあえず全部入れておこう」となりがちなオプションですが、全URLに同じ日付が並ぶなら出さないほうがすっきりします。
入れるなら、ページごとに正しい日付を出せるようになってから、が良さそうです。

serialize で URL ごとに加工・除外する

filter よりも細かく扱いたいときは serialize を使います。
サイトマップに書き出す直前に1件ずつ呼ばれる関数で、undefined を返すとそのURLを除外、item を書き換えて返すと内容を変えられます。

公式ドキュメントの例に沿うと、こんな形です。

// astro.config.mjs
import { defineConfig } from "astro/config";
import sitemap, { ChangeFreqEnum } from "@astrojs/sitemap";

export default defineConfig({
  site: "https://example.com",
  integrations: [
    sitemap({
      serialize(item) {
        // URL に「exclude-from-sitemap」を含むページは載せない
        if (/exclude-from-sitemap/.test(item.url)) {
          return undefined;
        }
        // 特定のページだけ値を書き換える
        if (/your-special-page/.test(item.url)) {
          item.changefreq = ChangeFreqEnum.DAILY;
        }
        return item;
      },
    }),
  ],
});

item.url にはページの完全なURLが入っています。
書き換えなかった item も return するのを忘れずに。何も返さないと undefined と同じ扱いになり、除外されてしまいます。

例の changefreq は、前の見出しのとおりGoogleは使わない値なので、あくまで書き方の例として見てください。

オプション一覧

ここまで紹介したものも含めて、@astrojs/sitemap 3.7.4 で指定できる主なオプションをまとめておきます。

オプション既定値内容
filter—ページごとに載せるかを決める関数。引数は完全なURL
customPages—Astroが管理していないページのURLを追加する
customSitemaps—外部のサイトマップを index に追加する(3.5.0〜)
entryLimit450001ファイルに入れるURL数の上限。超えると次のファイルに分かれる
changefreq / priority / lastmod—全URLに同じ値を付ける
serialize—書き出す直前に1件ずつ加工・除外する関数
i18n—多言語サイト向けに、既定の言語と各言語の対応を指定する
xslURL—サイトマップに適用するXSLスタイルシートのURL(3.2.0〜)
namespacesすべて有効news・xhtml・image・video の名前空間を出すかどうか(3.6.0〜)
chunks—条件ごとにサイトマップを複数のファイルに分ける(3.7.0〜)
filenameBasesitemap出力ファイル名の先頭部分(3.4.0〜)

サイトマップが生成されない・反映されないときの確認ポイント

「導入したはずなのにサイトマップが見当たらない」「載っているはずのページがない」というときは、次の順番で見ていくと原因を絞りやすいです。

上から順に確認する
  • astro.config.mjs に site を設定しているか(未設定だと警告だけ出てスキップされる)
  • 開発サーバーではなく、pnpm build のあとの dist/ を見ているか
  • 載っていないのが、オンデマンドレンダリング(SSR)する動的ルートのページではないか
  • filter や serialize で、意図せず外していないか
  • デプロイ先のビルド成果物に sitemap-index.xml が含まれているか

なお、サイトマップの対象になるページが1件もないときも、警告を出すだけでサイトマップは作られません。

見落としやすいのが、3つ目のオンデマンドレンダリングのページです。
@astrojs/sitemap は、SSRで動かしている動的ルートについてはサイトマップのエントリを作れません。

一方で、getStaticPaths() を使ってビルド時にURLが決まるページは、動的ルートでもサイトマップに載ります。
記事ページや一覧ページを getStaticPaths() で静的に生成しているなら、この点は心配いりません。

getStaticPaths() の書き方や、SSRに切り替えたときの違いは別記事で整理しています。

最後のデプロイ先は、ローカルの dist/ にはできているのに、本番のURLで開くと見つからないケースです。
ホスティング側のビルドコマンドや出力ディレクトリの設定が、ローカルと同じになっているかを確認してみてください。

まとめ|サイトマップは作ったあと「場所を伝える」まで

@astrojs/sitemap を使えば、Astroのサイトでもビルドのたびにサイトマップを自動で書き出せます。
押さえる設定は多くなく、site を忘れずに書くことと、できたサイトマップの場所を伝えることの2つが中心です。

changefreq や lastmod などのオプションは、入れればよいというものではありません。
まずは既定のまま動かして、外したいページが出てきたら filter や serialize を足していくのが扱いやすいと思います。

この記事のまとめ
  • @astrojs/sitemap は pnpm astro add sitemap で追加でき、ビルド時に sitemap-index.xml と sitemap-0.xml を書き出す
  • site が未設定だとエラーではなく警告だけでスキップされるので、ログを確認しておく
  • 開発サーバーでは生成されないので、確認は pnpm build のあとの dist/ で行う
  • サイトマップの場所は robots.txt・head の <link rel="sitemap">・Search Console で伝えられる
  • Googleは changefreq と priority を使わず、lastmod オプションは全URLに同じ日付が付く点に注意
  • 載せたくないページは filter か serialize で外せる
らるじゅらるじゅ

サイトマップは一度入れてしまえば、あとはビルドのたびに勝手に作り直してくれる、手のかからない仕組みです。
まずは site の設定と、ビルド後の dist/ の確認から始めてみてください!