
Astro 5からAstro 7へ段階的にアップグレードした
Cloudflare Workersで動かしているこのブログのAstroを、5.16.2から7.1.0へアップグレードしました。
2つのメジャーバージョンをまたぐため、今回は Astro 5 → 6 → 7 の順に更新しています。途中でビルドと型チェックを行い、問題が起きたバージョンを特定しやすくするためです。
この記事では、実際に変更した設定と、作業中に遭遇したエラー、その解決方法をまとめます。
アップグレード前後のバージョン
主なパッケージの変更は次のとおりです。
| パッケージ | 更新前 | 更新後 |
|---|---|---|
astro | 5.16.2 | 7.1.0 |
@astrojs/cloudflare | 12.6.12 | 14.1.3 |
@astrojs/mdx | 4.3.12 | 7.0.3 |
@astrojs/rss | 4.0.14 | 4.0.19 |
@astrojs/sitemap | 3.6.0 | 3.7.3 |
wrangler | 4.56.0 | 4.111.0 |
Astro 7でも既存のRemarkプラグインを使うため、@astrojs/markdown-remarkの7.2.1も追加しました。
更新前にnpm auditを実行すると、wranglerやminiflareが依存するundici、wsに、Highを含む7件の脆弱性が検出されました。アップグレード後は0件になっています。
事前確認
Node.jsのバージョン
Astro 6以降はNode.js 22.12.0以上が必要です。ローカルだけでなく、CIやデプロイ環境も確認します。
node -v
今回の環境はv22.20.0だったため、そのまま進められました。
破壊的変更の影響範囲
Astro 6では古いContent Collections APIが削除され、Content Layer APIへの移行が必須です。このブログではすでにsrc/content.config.tsでglob()ローダーを使っていたため、大きな移行は不要でした。
import { glob } from "astro/loaders";
import { defineCollection } from "astro:content";
const blog = defineCollection({
loader: glob({
base: "./src/content/blog",
pattern: "**/*.{md,mdx}",
}),
// ...
});
次のような古いAPIを使っている場合は、先に置き換える必要があります。
entry.slugentry.render()getEntryBySlug()Astro.glob()type: "content"を使った旧コレクション定義
公式の移行ガイドも確認しておきます。
作業ブランチを作る
アップグレード専用のブランチを作りました。
git switch -c upgrade/astro-7
作業ツリーがクリーンな状態で始めると、package-lock.jsonを含む変更を追いやすくなります。
Astro 5から6へアップグレード
まずAstro 6系と、対応する公式インテグレーションへ更新しました。
npm install \
astro@6.4.8 \
@astrojs/cloudflare@13.7.0 \
@astrojs/mdx@6.0.3 \
@astrojs/rss@4.0.19 \
@astrojs/sitemap@3.7.3 \
wrangler@4.111.0
Wranglerも同時に上げる
最初はwranglerを古い4.56.0のままにしていたため、インストール時にERESOLVEが発生しました。
peer wrangler@"^4.83.0" from @astrojs/cloudflare@13.7.0
@astrojs/cloudflare@13.7.0はwrangler@^4.83.0を要求します。今回は脆弱性もまとめて解消するため、最新の4.111.0へ更新しました。
--forceや--legacy-peer-depsで依存関係の不整合を隠すのではなく、要求されるバージョンに揃えています。
Zodのimport先を変更する
Astro 6ではContent Collectionsのスキーマに使うZodがv4になりました。zのimport先をastro:contentからastro/zodへ変更します。
import { glob } from "astro/loaders";
import { defineCollection } from "astro:content";
import { z } from "astro/zod";
今回のスキーマではz.coerce.date()などがそのまま動きましたが、Zod 4では変換後の型やデフォルト値の扱いが変わるケースがあります。複雑なスキーマを使っている場合は、ビルド時のバリデーション結果も確認した方が安全です。
Cloudflareアダプターのエントリーポイントを変更する
Astro 6対応のCloudflareアダプターでは、Wranglerのmainがビルド成果物ではなく、アダプターが提供する共通エントリーポイントを指すようになりました。
{
"main": "@astrojs/cloudflare/entrypoints/server"
}
変更前の設定を残すと、ビルド時に次のエラーが発生します。
The provided Wrangler config main field
(.../dist/_worker.js/index.js) doesn't point to an existing file
platformProxyを削除する
以前の設定ではCloudflareアダプターにplatformProxyを渡していました。
adapter: cloudflare({
platformProxy: {
enabled: true,
},
}),
Astro 6対応版ではこのオプションが存在しないため、単純な呼び出しに変更します。
adapter: cloudflare(),
残したままだと、型チェックで次のエラーになります。
Object literal may only specify known properties,
and 'platformProxy' does not exist in type 'Options'.
ここまででAstro 6のビルドと型チェックを実行し、いったんコミットしました。
npm run build
npx tsc --noEmit
git commit -am "chore: upgrade to Astro 6"
Astro 6から7へアップグレード
Astro 6で正常に動くことを確認してから、Astro 7と対応パッケージへ進みます。
npm install \
astro@7.1.0 \
@astrojs/cloudflare@14.1.3 \
@astrojs/mdx@7.0.3 \
@astrojs/markdown-remark@7.2.1
既存のRemarkプラグインを維持する
Astro 7のデフォルトMarkdownプロセッサーは、Rust製のSätteriに変更されました。
このブログでは次のRemarkプラグインを使っています。
- YouTube URLを
iframeへ変換する独自プラグイン - URLをリンクカードに変換する
remark-link-card - Mermaidコードブロックを処理する
astro-mermaid
既存のRemark/Rehypeパイプラインを維持するため、@astrojs/markdown-remarkのunified()を明示的に設定しました。
import { unified } from "@astrojs/markdown-remark";
export default defineConfig({
markdown: {
processor: unified({
remarkPlugins: [
remarkYouTube,
[
remarkLinkCard,
{
cache: true,
shortenUrl: true,
},
],
],
}),
},
});
markdown.remarkPluginsへ直接指定する形式も一時的には動作しますが、Astro 7では非推奨警告が出ます。プラグインをunified()へ渡すことで警告を解消できます。
Rustコンパイラーによるチェック
Astro 7ではRust製コンパイラーがデフォルトかつ唯一のコンパイラーになりました。閉じタグの不足など、以前は許容されていた無効なHTMLがエラーになる可能性があります。
今回のビルドでは.astroファイルの修正は不要でしたが、メジャーアップデート後は全ページをビルドし、可能なら表示も確認するのが安全です。
CloudflareでHTMLが[object Object]になる問題
Astro 7への更新後、ビルド自体は成功しました。しかし、Cloudflareアダプターを通して生成されたHTMLを確認すると、全ページが次の15文字だけになっていました。
[object Object]
Cloudflareアダプターを外すと正常なHTMLが生成されたため、Markdownやページ実装ではなく、Workersランタイムとの互換性が原因だと切り分けられました。
これはnodejs_compatで有効になるprocess v2をAstroがNode.js環境として誤検出し、WorkersのResponseが扱えない形式で本文を返す既知の問題です。
今回はwrangler.jsonにdisable_nodejs_process_v2を追加しました。
{
"compatibility_date": "2026-07-17",
"compatibility_flags": [
"nodejs_compat",
"disable_nodejs_process_v2"
]
}
この変更後、Cloudflareアダプターを有効にした状態でも完全なHTMLが生成されるようになりました。
新しいcompatibility_dateでは別のランタイム機能によって解消される場合もありますが、アップデート後はビルドの終了コードだけでなく、生成されたHTMLやプレビューのレスポンス本文まで確認した方が安全です。
ヒーロー画像が消える問題
デプロイ後、記事のヒーロー画像が表示されなくなりました。
原因は、@astrojs/cloudflareのデフォルト画像サービスがcompile(ビルド時変換)からcloudflare-binding(ランタイム変換)へ変わったことです。HTML上の画像URLが次のような形式になります。
<img src="/_image?href=%2F_astro%2Fhero....png&w=1020&h=510" ...>
静的アセットへの直接参照ではなく、Workers経由の画像変換エンドポイントを使うため、バインディングやランタイムの条件によっては画像が壊れます。
このブログは静的配信が主なので、ビルド時に画像を変換する設定へ戻しました。
adapter: cloudflare({
imageService: "compile",
}),
再ビルド後は、従来どおり静的ファイルを参照するURLになります。
<img src="/_astro/hero.....webp" ...>
静的アセットの出力先を更新する
新しいCloudflareアダプターでは、静的アセットがdist/clientへ出力されます。Wranglerの設定も合わせて変更しました。
{
"assets": {
"directory": "./dist/client",
"binding": "ASSETS"
}
}
最終的なwrangler.jsonの要点は次のとおりです。
{
"name": "blog",
"compatibility_date": "2026-07-17",
"compatibility_flags": [
"nodejs_compat",
"disable_nodejs_process_v2"
],
"main": "@astrojs/cloudflare/entrypoints/server",
"assets": {
"directory": "./dist/client",
"binding": "ASSETS"
}
}
最終確認
最後に、ビルド、型チェック、デプロイのドライランを実行しました。
npm run build
npx tsc --noEmit
npx wrangler deploy --dry-run
npm audit
確認結果は次のとおりです。
- 全19ページの静的生成に成功
- TypeScriptのエラーなし
- Wranglerのドライラン成功
- YouTube埋め込みが生成されたHTMLに存在
- リンクカードが生成されたHTMLに存在
- 各記事のHTMLが
[object Object]ではなく正常な内容を持つ npm auditの脆弱性は0件
Remark Link Cardが外部サイトからOpen Graph情報を取得できず、警告を出すURLはありました。ただし、これはアップグレード前からある外部サイト側の応答によるもので、ビルドは成功しています。
まとめ
Astro 5から7へのアップグレードは、Content Layer APIへ移行済みであればコード本体の変更は多くありませんでした。一方で、Cloudflare Workersと組み合わせる場合は、次の設定変更が重要でした。
- Astroと公式インテグレーションを対応するメジャーバージョンへ揃える
wranglerのpeer dependencyも同時に更新する- Zodを
astro/zodからimportする - Wranglerの
mainをCloudflareアダプターの共通エントリーポイントへ変更する - Remarkプラグインを
unified()プロセッサーへ移す nodejs_compatによる[object Object]問題をランタイム設定で回避する- 画像サービスを
imageService: "compile"にしてビルド時変換へ戻す dist/clientを静的アセットの出力先として確認する
メジャーバージョンを一度に上げること自体よりも、各段階でビルド・型チェック・生成物の確認を行うことが重要でした。特に今回の[object Object]問題はビルドが成功していたため、終了コードだけを見ていたら見逃していた可能性があります。