Astro 7.4 が2026年10月15日に出ました。7.3は前のリリースの穴埋めが中心でしたが、7.4は「ビルドが遅い」という悩みに向けた変更が中心です。
astro build --timingsで、ビルド時間がどこで使われたかを一覧できる- 実験的機能として、静的ページを複数のCPUコアで同時に描画できる
- 画像サービスを、ビルド時と実行時で別々に指定できる
ほかに、自前のエントリポイント向けの notFound() ハンドラー、フォント設定の警告、静的ビルドのリダイレクトページを自作できる実験的機能も入りました。
先に一つだけ注意しておきます。10月21日に出た7.4.2で、必要なNode.jsのバージョンが 22.23.4以上 に上がりました。同じ日に出たNode.jsのセキュリティリリースに合わせた変更です。Node.js 22系でこれより古いバージョンを使っていると、astro コマンドは起動直後にエラーで止まります。CIやホスティングのNode.jsのバージョンを固定している人は、Astroより先にそちらを確認してください。
このブログのようなアダプターなしの静的サイトでも、--timings、並列プリレンダリング、Node.jsの件の3つは関係します。画像サービスの分離と notFound() はオンデマンドレンダリングや自前のエントリポイントを使っている人向けです。
Astroを触ったことがある方向けですが、出てくる用語はその都度説明します。
Table of contents
Open Table of contents
リリースの中身
マイナーリリースなので、既存のコードが動かなくなる変更は基本的にありません。ただし、Node.jsの最低バージョンは上がりました。7.4.0で入った変更は次のとおりです。
| 変更点 | 触る場所 | ひとことで言うと |
|---|---|---|
| ビルド時間の内訳表示 | astro build --timings | どこが遅いかを数字で見る |
| 画像サービスの分離 | image.service.build / runtime | ビルド時はSharp、実行時は画像CDN、と分けられる |
notFound() ハンドラー | astro/fetch、astro/hono | 自前のエントリポイントでも404ページを返す |
| フォント設定の警告 | フォントプロバイダーの getFontProperties() | 存在しないweightなどを指定すると警告が出る |
| Node.jsの最低バージョン | 実行環境 | 22.22.0以上(7.4.2で22.23.4以上) |
| 並列プリレンダリング(実験的) | experimental.parallelPrerender | 静的ページを複数スレッドで描画する |
| カスタムリダイレクトページ(実験的) | experimental.redirectPage | 静的ビルドのリダイレクト用HTMLを自作する |
どの変更が関係するかは、Astroの使い方で変わります。使い方ごとに分けると次のとおりです。
その後、変更履歴によると、10月19日に7.4.1、10月21日に7.4.2が出ています。2026年10月24日時点の最新は7.4.2です。
アップグレードは公式のアップグレード手順どおり専用コマンドを使うのが楽です。Astro本体と公式インテグレーションをまとめて更新してくれます。
npx @astrojs/upgrade # npm
pnpm dlx @astrojs/upgrade # pnpm
yarn dlx @astrojs/upgrade # Yarn
@astrojs/cloudflare か @astrojs/markdoc を使っている場合は、Astro本体と同時に上げてください。7.4.0と同じ日に出た @astrojs/cloudflare 14.4.0と @astrojs/markdoc 2.1.0は、どちらも astro@^7.4.0 を必要とします。
ビルド時間の内訳を出す —timings
何が出るのか
ビルドが遅くなったとき、原因の候補はたくさんあります。Viteのプラグインかもしれないし、シンタックスハイライト(コードの色付け)かもしれないし、画像の変換や、特定の重いページかもしれません。これまでは、原因を探すのに設定を一つずつ外して試すしかありませんでした。
7.4から、astro build に --timings フラグを付けられます。
astro build --timings
ビルドが終わると、どこに何秒かかったかの要約が表示されます。CLIリファレンスによると、要約に入る項目は次のとおりです。
| 項目 | 中身 |
|---|---|
| ビルドフェーズ | 設定の読み込み、コンテンツの同期、バンドル、ページ生成などの段階ごとの時間 |
| Viteプラグイン | プラグインごとの時間と、バンドルに時間がかかったファイル |
| Markdown | remark/rehypeプラグインと、シンタックスハイライトの時間 |
| ページのレンダリング | ページごとの描画時間と、遅いページの一覧 |
| 画像 | 画像の最適化にかかった時間 |
| インテグレーション | インテグレーションのフックごとの時間 |
どこかを高速化する前に、まず遅い場所を確かめるための機能です。
リリース記事の例を読む
リリース記事では公式のblogスターターに <CommentSection> というコンポーネントを足した例で使い方を見せています。記事ごとにコメントを取得し、その中の <Comment> が投稿者のプロフィールを1件ずつ取得する作りです。
---
// src/components/Comment.astro
const { comment } = Astro.props;
// コメントごとに投稿者のプロフィールを取得する
const res = await fetch(`https://jsonplaceholder.typicode.com/users?email=${comment.email}`);
const [user] = await res.json();
---
<article>
<strong>{user?.name ?? comment.name}</strong>
<p>{comment.body}</p>
</article>
コードに間違いはありません。ただ、プロフィールの取得はコメント一覧が返ってくるまで始められません。そのため、どのページもネットワークの往復を2回、順番に待つことになります。この状態で --timings を付けてビルドすると、次のような要約が出ます。リリース記事の出力から一部を抜き出し、横棒のグラフは省きました。
build timings
total 2.61s · 9 pages · output "static"
Build phases
setup 225ms 8.6%
content sync 206ms 7.9%
prerender bundle 151ms 5.8%
generate pages 2.10s 80.6%
Page rendering (2.09s across 9 pages)
component render 2.08s 79.6%
page pipeline 13ms 0.5%
Slowest pages (median 297ms · p95 571ms)
/about 571ms
/blog/first-post 307ms /blog/[...slug]
/blog/using-mdx 303ms /blog/[...slug]
/rss.xml 10ms
/blog 6ms
上から順に読むと原因が絞れます。
generate pages(ページ生成)がビルド全体の約81%を占めている- その内訳を見ると、ほぼ全部が
component render(コンポーネントの中の処理)で、Astro自身の処理であるpage pipelineは0.5%しかない - 遅いページはどれも記事レイアウトを使うページで、
/blogや/rss.xmlは数ミリ秒で終わっている
この3段階の読み方と、たどり着いた原因を1枚にまとめます。
median は中央値、p95 は95パーセンタイル(遅い方から5%の位置の値)です。ここまで分かれば、記事レイアウトの中で描画している何かが遅い、と見当が付きます。
リリース記事は <CommentSection> の中で Promise.all() を使ってコメントと全員分のプロフィールを同時に取得し、プロフィールを <Comment> へ渡す形に直しています。Promise.all() は複数の非同期処理を同時に始めて、全部が終わるのを待つ関数です。これでページ生成は2.10秒から1.13秒になり、記事ページ1枚あたりの時間は半分になりました。
修正後のコードはリリース記事に載っていません。たとえば次のように書けます。
---
// src/components/CommentSection.astro(筆者が書いた一例)
import Comment from './Comment.astro';
const { postId } = Astro.props;
// 2つのリクエストを同時に送り、両方の結果を待つ
const [comments, users] = await Promise.all([
fetch(`https://jsonplaceholder.typicode.com/comments?postId=${postId}`).then((r) => r.json()),
fetch('https://jsonplaceholder.typicode.com/users').then((r) => r.json()),
]);
const userByEmail = new Map(users.map((user) => [user.email, user]));
---
{comments.map((comment) => (
<Comment comment={comment} user={userByEmail.get(comment.email)} />
))}
<Comment> 側は fetch() をやめて、Astro.props から user を受け取るだけにします。
使いどころ
リリース記事はこの後で紹介する並列プリレンダリングや、7.2で入ったインクリメンタルビルドを試す前の最初の一歩として --timings を勧めています。並列化で速くなるのは描画が遅いときで、遅いのが画像の変換やバンドルなら効果は小さくなります。どこが遅いかを先に確かめておけば、どの対策を選ぶべきかが分かります。
自分なら、Astroや依存パッケージを上げる前後に1回ずつ --timings を付けてビルドし、数字を残しておきます。上げた後に遅くなっても、どの段階が遅くなったのかをすぐ比べられるからです。
ビルド用と実行時用で画像サービスを分ける
プリレンダリングとオンデマンドレンダリング
Astroのページの作り方は2通りあります。
- プリレンダリング:ビルド時にHTMLを作っておく。いわゆる静的サイトのページ
- オンデマンドレンダリング:リクエストが来るたびにサーバーでHTMLを作る。サーバーやエッジ(利用者に近い場所で動く実行環境)でAstroを動かすには、アダプターが要る
画像サービスは <Image /> や getImage() の裏で画像を縮小したり形式を変えたりする部品です。組み込みの画像サービスはSharpという画像処理ライブラリを使います。
2種類のページでは、画像処理の向き不向きが違います。ビルド時は時間に余裕があり、Node.jsの機能もすべて使えるので、Sharpのように手元で変換する方式が向いています。一方、オンデマンドのページはサーバーやエッジで動きます。Cloudflare Workersのように、ネイティブモジュール(C言語などで書かれた部品)を含むSharpを動かせない環境も多く、画像CDN(画像の変換と配信を引き受けるサービス)に任せる方が向いています。
これまでは、画像サービスを1つだけ選ぶか、アダプターに選んでもらうしかありませんでした。お弁当屋さんで言えば、作り置きの弁当と注文を受けてから作る弁当を、同じ厨房で作るしかなかったようなものです。2種類のページの条件と、向いている画像サービスを並べると次のようになります。
7.4での変更
7.4から、image.service に build と runtime の2つを指定できます。
// astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
image: {
service: {
build: { entrypoint: 'astro/assets/services/sharp' },
runtime: { entrypoint: 'my-image-cdn-service' },
},
},
});
my-image-cdn-service は、使いたい画像CDN向けの画像サービスに置き換えてください。
| サービス | 担当する場面 | 向いている実装 |
|---|---|---|
build | プリレンダリングするページの画像(ビルド時)と、開発サーバー | Sharpなど手元で変換するもの |
runtime | オンデマンドのページの画像と、本番の画像エンドポイント | 画像CDNなど |
これまでどおり、サービスを1つだけ指定する書き方も使えます。その場合は両方の場面で同じサービスが使われます。
設定リファレンスによると、プリレンダリングするページの画像は、ビルド時に必ずNode.jsで生成されます。そのため、アダプターが別の実行環境でプリレンダリングする場合でも、build にはSharpを指定できます。
この変更のために、ビルド中に使われた画像を追跡する仕組みが作り直されました。プリレンダラー(ビルド時にページを描画する部品)は、画像の処理を自前で再現せず、Astro本体の画像パイプラインに乗るようになりました。その結果、@astrojs/cloudflare も、プリレンダリングするページの画像をほかのアダプターと同じ経路で処理するようになっています。
インテグレーション作者向けの変更
インテグレーションを自作していない人は、この節を読み飛ばして構いません。
一つ目は設定オブジェクトの形です。config.image.service は利用者が書いた形のまま渡されます。利用者が build と runtime を指定した場合、config.image.service.entrypoint と config.image.service.config は undefined になります。画像サービスを読むインテグレーションは、runtime プロパティがあるかを確かめてください。
'astro:config:done': ({ config }) => {
const { service } = config.image;
const runtimeService = 'runtime' in service ? service.runtime : service;
// runtimeService.entrypoint を読む
},
updateConfig() で image.service を設定するときも注意が要ります。設定済みの値と形が違う場合は、マージ(結合)されずに置き換わります。たとえば build と runtime を使っているプロジェクトへ単一のサービスを設定すると、両方とも置き換わります。
二つ目はカスタムプリレンダラーです。setPrerenderer() でAstro標準のプリレンダラーを包んでいる場合は、getStaticPaths() と render() が返すメタデータ(ページで使った画像の情報)を、そのまま引き継いでください。
setPrerenderer((defaultPrerenderer) => ({
name: 'my-prerenderer',
async setup() {
await defaultPrerenderer.setup?.();
},
async getStaticPaths() {
const result = await defaultPrerenderer.getStaticPaths();
const { paths, metadata } = Array.isArray(result) ? { paths: result } : result;
// 下書きのページを除外しつつ、metadata は引き継ぐ
return { paths: paths.filter(({ pathname }) => !pathname.startsWith('/drafts')), metadata };
},
render(request, options) {
return defaultPrerenderer.render(request, options);
},
async teardown() {
await defaultPrerenderer.teardown?.();
},
}));
setup() と teardown() も、Astro標準のプリレンダラーへそのまま渡してください。Astro標準のプリレンダラーは、setup() の中でビルド済みのアプリを読み込みます。setup() を書かないと、アプリを読み込まないまま getStaticPaths() が呼ばれ、ビルドが失敗します。
getStaticPaths() から配列だけを返す書き方や、render() から Response だけを返す書き方も、まだ動きます。ただし非推奨になり、そのページで使った画像は生成されません。ビルドは通るのに画像だけが欠けるので気付きにくく、早めに直しておくのが無難です。
自前のエントリポイント向けのnotFound()
Astro 7.0の高度なルーティングでは、Astroのリクエスト処理を部品に分けて、自分で組み直せます。部品は astro/fetch と astro/hono から取り出します。既定の処理を丸ごと走らせる astro() のほかに、ミドルウェアを走らせる middleware()、ルートに一致したページを描画する pages() などの個別のハンドラー(処理を受け持つ関数)があります。Cloudflare Workersのworkerエントリポイントを自分で書くときによく使います。詳しくは7.3の記事で説明しました。
ここに穴がありました。astro() を使わずに pages() を直接使うと、どのルートにも一致しないリクエストに対して、空の404が返っていました。src/pages/404.astro を用意していても、プリレンダリング済みでも同じです。変更履歴によると、内部向けの X-Astro-Error ヘッダーだけが付いた、中身のないレスポンスです。
7.4.0で notFound() ハンドラーが入りました。pages() より前に置くと、一致するルートがないときに404ページを描画して返します。7.3までとの違いは次のとおりです。
Honoで書いたCloudflare Workersのエントリポイントなら、次のようになります。HonoはWorkersなどで動く軽量なWebフレームワークです。
// src/worker.ts
import { Hono } from 'hono';
import { notFound, pages } from 'astro/hono';
import { cf } from '@astrojs/cloudflare/hono';
const app = new Hono();
app.use(cf());
app.use(notFound());
app.use(pages());
export default app;
astro/fetch 版も同じ名前で用意されています。astro/fetch のリファレンスによると、ルートが一致したときは undefined を返すので、そのまま後続の処理へ進めます。
// src/fetch.ts
import { FetchState, middleware, notFound, pages } from 'astro/fetch';
export default {
async fetch(request: Request): Promise<Response> {
const state = new FetchState(request);
const notFoundResponse = await notFound(state);
if (notFoundResponse) return notFoundResponse;
return middleware(state, (s) => pages(s));
},
};
リファレンスには、過剰にエンコードされたパスへのリクエストに対しては、404ではなく空の400を返すとも書かれています。
astro() には最初からこの処理が入っています。notFound() が必要なのは、ハンドラーを自分で組み合わせている場合だけです。
フォント設定の警告
Astroのフォント機能(fonts 設定)では、Google Fontsなどの提供元をフォントプロバイダーとして指定し、使うweight(太さ)、style(斜体かどうか)、subset(文字の範囲)、ファイル形式を選びます。
ところが、そのフォントファミリーが持っていないweightやsubsetを指定しても、これまでは何も言われませんでした。見出しを 700 で指定したのに細いまま、といった見た目の違和感で初めて気付くことになります。
7.4.0から、フォントプロバイダーは getFontProperties() という任意のコールバックを実装できます。そのファミリーが実際に持っているweight、style、subset、形式を返す関数です。Astroは設定に書かれた値のうちプロバイダーが提供できないものについて、1つずつ警告を出します。
400と700しか持たないフォントに300も指定した場合で、前後を比べてみます。
import type { FontProvider } from 'astro';
const provider: FontProvider = {
name: 'my-provider',
resolveFont: ({ familyName }) => {
// ...
},
getFontProperties: ({ familyName }) => ({
weights: ['400', '700'],
styles: ['normal', 'italic'],
subsets: ['latin'],
formats: ['woff2'],
}),
};
フォントプロバイダーのリファレンスによると、weightは "400" のような単独の値のほか、可変フォントなら "100 900" のような範囲でも書けます。知らないファミリーなら undefined を返せば、そのファミリーの確認は飛ばされます。
組み込みのフォントプロバイダーはすべて対応済みです。利用者は何もしなくても、上げるだけで警告が出るようになります。このブログもフォント機能でGoogle Fontsのフォントを複数のweightで読み込んでいるので、上げたらまずビルドログに警告が出ていないかを見るつもりです。
フォントプロバイダーを自作している人は、今のうちに getFontProperties() を実装しておくよう勧められています。Astro 7では任意ですが、Astro 8で必須になる予定です。
もう一つ、フォントプロバイダーの init() に渡されるコンテキストに fetch() 関数が加わりました。一時的な失敗を自動で再試行してくれる fetch() です。unifont(Astroのフォント機能が内部で使うライブラリ)のプロバイダーを包んで作る場合は、このコンテキストをそのまま渡せます。
Node.jsの最低バージョンが上がる
7.4.0で22.22.0、7.4.2で22.23.4
7.4.0で、Astroと公式インテグレーションが対応するNode.jsの最低バージョンが22.22.0になりました。ブラウザ上でNode.jsを動かすStackBlitzが対応している、Node.js 22系の最新版に合わせた変更です。
さらに7.4.2で、最低バージョンが22.23.4に上がりました。2026年10月21日に出たNode.jsのセキュリティリリースを取り込むためです。このリリースでは10件の脆弱性が修正され、そのうち7件が22系に影響します。深刻度が最も高いのは「High」で、DNSの名前解決や証明書の検証、Brotli(圧縮形式の一つ)の展開処理に関するものが含まれます。
| Astro | 最低のNode.js | 理由 |
|---|---|---|
| 7.3系 | 22.12.0 | 7.0からの値 |
| 7.4.0、7.4.1 | 22.22.0 | StackBlitzが対応する22系の最新版に合わせた |
| 7.4.2 | 22.23.4 | 2026年10月のNode.jsセキュリティリリースを取り込んだ |
パッチリリースで最低バージョンが上がるのは珍しく見えますが、ルールどおりの動きです。Astroのアップグレード方針では、Node.jsの脆弱性がAstroに影響する場合、メンテナンスLTS(長期サポート版のうち保守段階のもの)の最低バージョンをパッチリリースで上げてよい、と定めています。
古いNode.jsで起きること
package.json の engines 欄が変わるだけなら、パッケージマネージャーが警告を出す程度で済みます。ところが、Astroのコマンド本体にも同じ条件が書き込まれています。7.4.2の bin/astro.mjs を読むと、メジャーバージョンが23以下のNode.jsで >=22.23.4 を満たさない場合、何もせずにエラーで終了します。
つまり、Node.js 22.22.0を使っているCIでAstroを7.4.2に上げると、astro build がその場で止まります。逆に、Node.js 24以降はこの確認自体が飛ばされます。使っているバージョンごとの動きをまとめると次のとおりです。
確認しておきたい場所は次のとおりです。
- 手元:
node -vで22.23.4以上か、Node.js 24系以降か - CI:GitHub Actionsの
actions/setup-nodeなどで指定しているバージョン - ホスティング:Netlify、Vercel、Cloudflare Pagesなどのビルド設定にあるNode.jsのバージョン
.nvmrc、.node-version、Dockerのベースイメージ
自分のプロジェクトの package.json の engines も合わせて直しておくと親切です。このブログも >=22.12.0 のままなので、上げるときに直す必要があります。
なお、Node.js 24系を使っている場合も、同じセキュリティリリースで24.22.1が出ています。Astroの起動条件とは関係ありませんが、こちらも上げておくのが無難です。
実験的機能:並列プリレンダリング
何が変わるのか
Astroは静的ページを並行して描画しますが、これまではすべて1つのスレッド(プログラムの実行の流れ)の上で動いていました。JavaScriptは1つのスレッドで1つの処理しか実行できません。fetch() の待ち時間のような「待ち」は重ねられても、計算の重いページは1ページずつしか処理できません。CPUのコアがいくつあっても、使えるのは1つだけでした。
7.4.0で入った experimental.parallelPrerender フラグを有効にすると、静的ページをNode.jsのワーカースレッドで描画します。ワーカースレッドは1つのプロセスの中で別々に動くJavaScriptの実行環境です。それぞれが別のCPUコアを使えます。レジが1台しかなかったスーパーに、レジを何台も増やすようなものです。
// astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
experimental: {
parallelPrerender: true,
},
});
既定では使えるCPUコアのうち1つを残して全部使います。ワーカーを増やすほどメモリの使用量も増えます。ビルドがメモリ不足で落ちる場合や、速くならない場合は、workers で数を減らします。
// astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
experimental: {
parallelPrerender: {
workers: 4,
},
},
});
各ワーカーはbuild.concurrency で指定した数のページを同時に描画します。build.concurrency の既定値は1なので、既定のままならワーカー数がそのまま同時に描画するページ数になります。
7.2で入ったインクリメンタルビルドとも相性が良い、とリリース記事は書いています。インクリメンタルビルドが変更のないページを飛ばし、並列プリレンダリングが残りのページを複数のコアに振り分ける、という分担です。7.2の時点では、build.concurrency を1より大きくするとインクリメンタルビルドが機能しませんでしたが、7.3で修正されています。
制限と注意点
並列プリレンダリングのドキュメントには、次の制限が書かれています。
| 制限 | 何が起きるか |
|---|---|
| モジュールの変数を共有しない | ページの描画中にモジュールのトップレベルの変数へ入れておいた値が、別のページの描画時には無いことがある |
getStaticPaths() の props はシリアライズできる値に限る | 関数やクラスのインスタンスを含むページは並列に描画できない |
| アダプター独自のプリレンダリングとは併用できない | 公式アダプターでは @astrojs/cloudflare が該当し、フラグは無視されてビルド時に警告が出る |
一つ目は気付かずに踏みやすい制限です。たとえば、APIの結果をモジュールのトップレベルの Map に入れて、ページ間で使い回しているとします。シングルスレッドなら最初のページで1回取得すれば済みますが、ワーカーごとにメモリが分かれるので、ワーカーの数だけ取得が走ります。速度が出ないだけならまだしも、APIの呼び出し回数制限に引っかかるかもしれません。ページ間で値を共有したいなら、コンテンツコレクションやファイルなど、スレッドの外に置く方法を考えてください。ワーカーが3つの場合を図にすると次のようになります。
二つ目の「シリアライズ」は、値をスレッド間で受け渡せるデータの形に変換することです。数値、文字列、配列、ふつうのオブジェクトは問題ありません。関数やクラスのインスタンスは変換できません。
自分なら、まず --timings でページ生成がビルド時間の大半を占めていることを確かめてから試します。ページ数が少ないサイトや、時間の大半がネットワークの待ちで占められているサイトでは、ワーカーを起動する手間の方が大きくなることもあります。実験的機能なので、本番のビルドに入れる前に、生成されたHTMLが変わらないことも確かめておくと安心です。
実験的機能:カスタムリダイレクトページ
静的サイトのリダイレクトの仕組み
リダイレクトはあるURLへのアクセスを別のURLへ転送する仕組みです。サーバーがあれば、ステータスコード301や302と一緒に Location ヘッダーで転送先を返せます。
静的サイトには、ヘッダーを組み立てて返すサーバーがありません。そこでAstroはリダイレクトごとに <meta http-equiv="refresh"> タグ入りの小さなHTMLを生成します。このタグは指定した秒数の後に別のURLへ移動するようブラウザへ指示します。対象は次の3つです。
- 設定ファイルの
redirects - プリレンダリングするページでの
Astro.redirect() - i18n(多言語対応)のリダイレクト
このHTMLの中身、文言、待ち時間は固定されていて、デザインを合わせたり日本語に訳したりはできませんでした。引っ越しの貼り紙を、自分の言葉で書けなかったようなものです。
7.4での変更
experimental.redirectPage を true にすると、このページを自作できます。
// astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
experimental: {
redirectPage: true,
},
});
続いて src/pages/3xx.astro を作ります。Astroはリダイレクトごとにこのページを1回描画し、そのリダイレクトの情報をpropsとして渡します。日本語のサイトなら、たとえば次のように書けます。
---
// src/pages/3xx.astro
import type { RedirectPageProps as Props } from 'astro';
const { from, to, status, delay } = Astro.props;
---
<html lang="ja">
<head>
<meta http-equiv="refresh" content={`${delay};url=${to}`} />
<meta name="robots" content="noindex" />
<title>ページを移動しました</title>
</head>
<body>
<p>このページは移動しました。<a href={to}>{to}</a> へ進んでください。</p>
</body>
</html>
リダイレクトページのドキュメントによると、渡されるpropsは次の4つです。
| prop | 型 | 中身 |
|---|---|---|
from | string | 転送元のパス |
to | string | 転送先 |
status | number | 301 や 302 などのステータスコード |
delay | number | meta refreshの待ち秒数。302 なら2、それ以外は0 |
/old から /new への301リダイレクトを例に、設定がpropsを経てmeta refreshタグになるまでを追うと次のようになります。
静的ビルドでは、<meta http-equiv="refresh"> タグそのものがリダイレクトの本体です。自作したページには to へ向かうこのタグを必ず入れてください。タグが無いか、転送先が to と違う場合は、ビルド時に警告が出ます。3xx.astro が無いか描画に失敗した場合は、組み込みのページに戻ります。
細かい挙動も書いておきます。
/3xxへ直接アクセスした場合は、ふつうのルート(3xx.html)としてビルドされ、propsは渡されない- フラグを無効にすると、
src/pages/3xx.astroはふつうのページとして扱われ、リダイレクトには組み込みのページが使われる - オンデマンドのページからのリダイレクトは変わらず、
Locationヘッダーを使う
仕様についての意見はRFCで受け付けています。
そのほかの変更と7.4系の修正
インテグレーションによる出力先の制御
7.4.0では、Viteが環境ごとに解決した outDir(出力先)を、client、server、prerenderの出力先を決める基準として扱うようになりました。インテグレーションやViteのプラグインが出力先を動かせます。カスタムプリレンダラーは setPrerenderer() の新しい outputDirectories コンテキストから最終的な出力先を受け取れます。Viteのビルドマニフェスト(どのファイルがどこへ出力されたかの一覧)も、すべての buildApp フックが終わるまで残るようになり、デプロイ用のインテグレーションから読めるようになりました(#18313)。
ビルドエラーを隠していた不具合の修正
7.4.0の修正のうち、静的サイトでも気を付けたいのが次の1件です。
glob()ローダーがコンテンツの同期中に起きた描画エラーを握りつぶしていた。remark/rehypeプラグインが例外を投げても、astro buildは終了コード0で成功していた
これが直ったので、今まで成功していたビルドが、7.4に上げた途端に失敗することがあります。このブログもremark/rehypeのプラグインを使っています。Markdownのプラグインを使っているサイトでビルドが落ちたら、まずエラーメッセージに出ているプラグインと記事を確認してください。Astroの不具合ではなく、元から起きていたエラーが見えるようになっただけの可能性が高いです。7.3までと7.4からの違いを並べておきます。
同じく、@astrojs/cloudflare のように独自の実行環境でプリレンダリングするアダプターと src/fetch.ts を組み合わせた場合も、プリレンダリング中のエラーが握りつぶされていました。これまでは空のHTMLが書き出されてビルドが成功していましたが、7.4.0からはエラーでビルドが失敗します。
7.4.1と7.4.2の主な修正
変更履歴から、当てはまる人が多そうなものを選びました。
| 版 | 修正内容 |
|---|---|
| 7.4.1 | 開発サーバーの起動中にAstroの設定ファイルを編集するたびに、メモリ使用量が増えていく |
| 7.4.1 | パスにアポストロフィ(')を含むプロジェクトで、セッション、ミドルウェア、キャッシュプロバイダー、src/fetch.ts を読み込めない |
| 7.4.1 | アプリケーションのコードから astro/config をimportすると、Unterminated string でビルドが失敗する(共通モジュールで fontProviders を読み込む場合など) |
| 7.4.1 | 親ディレクトリに解決できない tsconfig.json があると、astro build が TSCONFIG_ERROR で失敗する |
| 7.4.2 | astro sync、astro check、astro build を実行すると、同じプロジェクトで動いている開発サーバーの最適化済み依存関係を置き換えてしまい、アイランドが動かなくなる |
| 7.4.2 | Linuxのスレッドに割り当てられたIDが残ったロックファイルを、動作中のAstroサーバーと誤認する。astro dev stop が無関係なプロセスを止める恐れがあった |
| 7.4.2 | 環境変数に $& などの置換パターンが含まれると、開発時に astro:env/server が正しく生成されない(Kittyターミナルが既定で設定する環境変数で起きていた) |
7.4.2の1件目は、AIエージェントに開発サーバーをバックグラウンドで動かしてもらいながら、astro check や astro build も実行させるような使い方で踏みやすい不具合です。開発サーバーのReactなどのコンポーネントが急に動かなくなった経験があるなら、これが原因かもしれません。
アップグレード前の確認
上げる順番も含めて、確認項目を並べておきます。
- Node.jsが22.23.4以上か、Node.js 24系以降かを、手元、CI、ホスティングのそれぞれで確かめる。足りなければ先にNode.jsを上げる
@astrojs/cloudflareと@astrojs/markdocを使っているなら、Astro本体と同時に上げる。@astrojs/upgradeを使えばまとめて上がる- インテグレーションやカスタムプリレンダラーを自作しているなら、
config.image.serviceの読み方と、setPrerenderer()のメタデータの引き継ぎを確認する - 上げた後にビルドが落ちたら、remark/rehypeプラグインのエラーが見えるようになっただけではないかを疑う
- 並列プリレンダリングを試す前に、
astro build --timingsで今のビルドの内訳を記録しておく
5つの手順を順番に並べると、次のようになります。
要点
- Astro 7.4は2026年10月15日リリースのマイナーバージョンです。2026年10月24日時点の最新は7.4.2で、Node.jsの最低バージョンが22.23.4に上がっています。条件を満たさない22系のNode.jsでは
astroコマンドが起動しないので、CIとホスティングの設定を先に確認します。 astro build --timingsで、ビルドフェーズ、Viteプラグイン、Markdown、ページの描画、画像、インテグレーションごとの所要時間を一覧できます。高速化に手を付ける前に、遅い場所を確かめるために使います。image.serviceにbuildとruntimeを分けて指定できるようになりました。プリレンダリングするページはSharp、オンデマンドのページは画像CDN、という使い分けができます。- 実験的な
experimental.parallelPrerenderは静的ページをワーカースレッドで並列に描画します。モジュールの変数を共有しない、propsはシリアライズできる値に限る、という制限があります。 - 実験的な
experimental.redirectPageで、静的ビルドのリダイレクト用HTMLをsrc/pages/3xx.astroとして自作できます。toへ向かう<meta http-equiv="refresh">タグは必ず入れます。
参考資料
- Astro 7.4 | Astro(2026年10月15日公開、2026年10月24日参照)
- astro CHANGELOG | withastro/astro(2026年10月24日参照。最新は7.4.2)
- Experimental parallel prerendering | Astro Docs(2026年10月24日参照)
- Experimental static redirect page | Astro Docs(2026年10月24日参照)
- Node.js Security Releases: October 2026 | Node.js(2026年10月21日公開、2026年10月24日参照)