Astro 7.3 が2026年9月3日に出ました。前の7.2がビルド時間に効く大きめの変更だったのに対し、7.3は、前のリリースで空いていた穴を埋めるリリースです。地味ですが、当てはまる人にはそれなりに効きます。
astro preview --ignore-lockで、プレビューサーバーを複数同時に起動できる- カスタム画像サービスとキャッシュプロバイダーへ、Astroのロガーが渡される
@astrojs/cloudflareに、カスタムworkerエントリポイント向けのfinalize()ヘルパーが入る
一つ目はPlaywrightでE2Eテストを回している人、二つ目は画像サービスやキャッシュプロバイダーを自作している人、三つ目はCloudflare Workersで src/worker.ts を自分で書いている人向けです。このブログのような、アダプターなしの静的サイトには正直どれも関係ありません。どれにも当てはまらないなら、後半の「7.3系で入った修正」だけ読めば十分です。7.2の記事で制限として挙げた並列ビルドの件が外れているので、あれを読んで見送った方は見直してもいいと思います。
Astroを触ったことがある方向けですが、出てくる用語はその都度説明します。
Table of contents
Open Table of contents
リリースの中身
マイナーリリースなので、既存のコードを壊す変更はありません。7.3.0で追加された機能は次の3つです。
| 変更点 | 触る場所 | ひとことで言うと |
|---|---|---|
| プレビューサーバーの並行起動 | astro preview --ignore-lock | ロックファイルを無視してもう1台起動する |
| 画像サービスへのロガー | 各フックの末尾引数 logger | console.warn() の代わりに使う |
| キャッシュプロバイダーへのロガー | onRequest() の context.logger | 同上 |
同じ日に出た @astrojs/cloudflare 14.3.0 には finalize() ヘルパーが入りました。Astro本体の機能ではないですが、リリース記事が一緒に案内しているので、ここでも一緒に見ます。
なお、7.3.0の公開から3時間ほどで7.3.1が出ています。astro:assets を使うプロジェクトが起動もビルドもできなくなる不具合の修正なので、上げるなら最初から7.3.1以降にしてください。
アップグレードは、公式のアップグレード手順どおり専用コマンドを使うのが楽です。Astro本体と公式インテグレーションをまとめて更新してくれます。
npx @astrojs/upgrade # npm
pnpm dlx @astrojs/upgrade # pnpm
yarn dlx @astrojs/upgrade # Yarn
パッケージマネージャーから直接更新する場合は astro@latest を指定します。Yarn 2以降では yarn upgrade --latest が動かないため、yarn add astro@latest を使ってください。
プレビューサーバーの並行起動
ロックファイルの経緯
Astro 7.0から、astro dev はAIコーディングエージェントから呼ばれたことを検知すると、自動的にバックグラウンドプロセスとして起動するようになりました。エージェントの端末を占有しないためです。このとき、同じプロジェクトでサーバーが二重に立ち上がるのを防ぐために、.astro/dev.json というロックファイルへURL、ポート、PID(プロセスID)を記録します。
このロックは便利な反面、同じプロジェクトで意図的に2台立てたい場面では邪魔になります。そこで7.1で astro dev --ignore-lock が入り、ロックファイルを読みも書きもせずに起動できるようになりました。
7.2では astro preview にも同じロックが入り、.astro/preview.json が作られるようになりました。ところが、逃げ道の --ignore-lock は astro dev にしか付いていませんでした。それで、PlaywrightのE2E(End-to-End)テストで設定違いのビルドを複数のプレビューサーバーで同時に検証していた人が、7.2に上げた途端に次のエラーで止まったとIssueを上げています。
Another astro preview server is already running.
URL: http://localhost:4321
PID: 3755
Run `astro preview stop` to stop it, or use `astro preview --force` to replace it.
このメッセージは --force で置き換えられると案内していますが、7.3.1のソースコードを読む限り、置き換え処理はバックグラウンド起動の経路にしかありません。普通の端末で astro preview --force と打っても、既存サーバーの検出で同じエラーになります。置き換えたいなら、astro preview stop で止めてから起動するか、astro preview --background --force を使ってください。AIエージェント検出時は自動でバックグラウンド経路に入るので、そのときだけ --force 単独でも置き換わります。
Issueを上げた人は --force も --background も試していますが、Playwrightの webServer はどちらもプロセスの早期終了として扱うので、解決になりませんでした。
ここまでの経緯を、astro dev と astro preview の2行で並べると次のようになります。
7.3での変更
7.3.0で astro preview にも --ignore-lock が付きました。
astro preview --ignore-lock --port 4322
挙動は astro dev --ignore-lock と同じです。CLIリファレンスに書いてあるのは次の3点。
- ロックファイルの存在を確認せず、書き込みもしない。すでに動いているサーバーがあっても、その横で起動する
- 起動したサーバーは
astro preview stop、status、logsの管理対象にならない --backgroundや--forceと同時に指定するとエラーになる。どちらもロックファイルを前提にした機能だからです
リリース記事にもあるとおり、短時間だけ使う使い捨てのサーバー向けの機能です。長く動かして stop や status で面倒を見たいサーバーは、これまでどおり --background で起動してください。
自分なら --port は毎回付けます。Astroの静的プレビューサーバーはViteのプレビューサーバーをそのまま使っていますが、アダプターが提供するプレビューサーバーではポートが埋まっていたときの挙動が変わり得ます。公式ドキュメントの例も --port 4322 を付けています。
AIエージェント環境での注意
落とし穴が一つ。AIエージェントから呼ばれたと判定されると、astro preview は自動的にバックグラウンドモードになります。ソースコードを読む限り、この自動判定も --background を付けたのと同じ扱いなので、--ignore-lock と衝突してエラーになります。エラーメッセージにも、自動検出されたAIエージェント環境とは併用できない旨が出ます。
Claude CodeのようなエージェントからPlaywrightを回す場合は、環境変数でバックグラウンド化を止めてから --ignore-lock を付けます。
ASTRO_PREVIEW_BACKGROUND=0 astro preview --ignore-lock --port 4322
環境変数の書式は、AIツールと組み合わせて開発するガイドにあります。
Playwrightの webServer へ書くなら、次のような形になります。プロジェクトごとに作業ディレクトリとポートを分け、どちらも --ignore-lock を付けます。
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
webServer: [
{
command: 'astro preview --ignore-lock --port 4321',
cwd: './fixtures/site-a',
url: 'http://localhost:4321',
},
{
command: 'astro preview --ignore-lock --port 4322',
cwd: './fixtures/site-b',
url: 'http://localhost:4322',
},
],
});
画像サービスとキャッシュプロバイダーへのロガー
Astroのロガーとは
Astro 7.0で入ったLogger APIは、Astroが出すログの行き先としきい値を設定で決められる仕組みです。astro.config.mjs の logger オプションに、組み込みの logHandlers.json()、logHandlers.console()、logHandlers.node()(既定)、複数をまとめる logHandlers.compose() のいずれか、または自作のロガーを指定します。
// astro.config.mjs
import { defineConfig, logHandlers } from 'astro/config';
export default defineConfig({
logger: logHandlers.json({ level: 'warn' }),
});
ログレベルは error、warn、info の3段階で、設定したレベル以上のメッセージだけが出ます。さらに、debug まで出す --verbose、何も出さない --silent というCLIフラグもあります。ページのレンダリング中に自分のログを混ぜたいときは、Astro.logger や context.logger から info()、warn()、error() を呼びます。この3つのメソッドを持つオブジェクトの型が AstroRuntimeLogger です。
7.1ではエントリポイントを URL で指定できるようになり、7.2ではプロジェクト相対パスも受け付けるようになりました。ロガー周りは、Astroのチームが毎リリース少しずつ手を入れている場所です。
何が困っていたか
ところが、Astroを拡張する側のコードには、このロガーが届いていませんでした。具体的には次の2つです。
- 画像サービス:
<Image />やgetImage()の裏で画像を変換する部品。組み込みはSharpで、Image Service APIを使って自作できる - キャッシュプロバイダー:オンデマンドレンダリングのレスポンスを、どこにどう保存するかを決める部品。組み込みは
memoryCache()で、Cache Provider APIを使って自作できる
対応していない画像形式を素通しするとき、Cookieを設定するレスポンスのキャッシュを飛ばすとき、これらが警告を出す手段は console.warn() しかありませんでした。console.warn() は設定したレベルも出力先も --silent も無視して、端末へ直接書き出します。JSONログを集約基盤へ送っている環境では、そこだけ素のテキストが混ざることになります。
画像サービス側の変更
7.3.0から、画像サービスの全フックが末尾の引数として logger を受け取ります。対象は getURL()、parseURL()、transform()、getHTMLAttributes()、getSrcSet()、validateOptions()、getRemoteSize() です。
import type { LocalImageService } from 'astro';
const service: LocalImageService = {
// ...
async transform(inputBuffer, transform, imageConfig, logger) {
logger.warn(`Could not optimize "${transform.src}". Passing it through unchanged.`);
return { data: inputBuffer, format: 'png' };
},
};
既存のサービスは引数が1つ増えただけなので、そのまま動きます。TypeScriptでも、受け取る引数が少ない関数は互換として扱われるため、型エラーにはなりません。
注意が要るのは、フックを自分で呼んでいるコードです。たとえば独自の画像エンドポイントを作り、getConfiguredImageService() で取ったサービスの parseURL() や transform() を直接呼んでいる場合は、エンドポイントの context.logger を末尾に渡してください。組み込みのSharpサービスは警告を出すときだけ logger に触るので、渡し忘れても普段は動いてしまい、問題のある画像に当たったときに初めて undefined の呼び出しで落ちます。公式ドキュメントのカスタムエンドポイントの例も、logger を渡す形に直っています。
Sharpサービスが logger 経由で出すようになった警告は、ソースコードを読む限り次の2つです。
- SVGを期待していたのに、元画像が別の形式だったとき。その形式のまま素通しする
- Sharpがデコードできない形式(アニメーションAVIFなど)だったとき。最適化せずにそのまま使う
キャッシュプロバイダー側の変更
キャッシュプロバイダーは、onRequest() に渡される context オブジェクトへ logger が追加されました。request、url、waitUntil() と並ぶ形です。
import type { CacheProvider } from 'astro';
const provider: CacheProvider = {
name: 'my-cache',
async onRequest({ request, url, logger }, next) {
logger.warn(`Skipping cache for ${url.pathname} because the response sets a cookie.`);
return next();
},
// ...
};
組み込みの memoryCache() も同じ経路を使うようになりました。ソースコードでは、次の3つの場面で logger.warn() を呼んでいます。
- レスポンスが
Set-Cookieを含むので、保存を飛ばした - レスポンスが
Vary: CookieまたはVary: *を含むので、保存を飛ばした(後述の修正で追加) - stale-while-revalidate のバックグラウンド再検証に失敗した
キャッシュが効かなかった理由が、設定したログの出力先へ流れてくるようになります。これまでは見えていませんでした。キャッシュヒット率が想定より低いときの調査が楽になるはずです。
同じPRで、作者はAstro内部に残っていた console 直書きの警告やエラーも、できる範囲で設定済みロガー経由へ置き換えています。
両方の変更点を1枚にまとめておきます。
Cloudflareのfinalize()ヘルパー
カスタムworkerエントリポイントとは
Astro 7.0で入った高度なルーティングは、Astroのリクエスト処理パイプラインを自分で組み直す仕組みです。既定では、末尾スラッシュの正規化、リダイレクト、セッション、Actions、ミドルウェア、ページのレンダリング、i18n、キャッシュという順で処理されます。src/fetch.ts に fetch() メソッドを持つオブジェクトをdefault exportすると、この順番へ自分の処理を差し込んだり、一部を省いたりできます。部品は astro/fetch モジュールから取り出します。リクエストごとの状態を持つ FetchState を先頭で作り、既定のパイプラインを丸ごと走らせる astro() か、middleware()、pages() のような個別ハンドラーへ渡します。
Cloudflare Workersでは、これをworkerのエントリポイントそのものとして書けます。wrangler.jsonc の main に ./src/worker.ts を指定し、Cloudflareの env(バインディング)と ExecutionContext を受け取る fetch() を自分で用意する形です。Durable Objectsやキューと同居させたいときに使います。書き方は2通りあります。
| 書き方 | 使う関数 | 特徴 |
|---|---|---|
| 丸ごと委譲 | @astrojs/cloudflare/handler の handle() | 既定のエントリポイントと同じ処理を関数1つで呼ぶ |
| 自分で組む | @astrojs/cloudflare/fetch の cf() と astro/fetch | 静的アセットの判定だけ cf() に任せ、残りは自由に組む |
cf() は @astrojs/cloudflare 13.6.0で入りました。FetchState、env、ExecutionContext を受け取り、静的アセットに当たれば Response を、Astroへ回すべきなら undefined を返す関数です。
何が抜けていたか
問題は、cf() で組んだエントリポイントと handle() の間で、挙動に差があったことです。2026年8月にIssueを立てた人が、同じプロジェクトで main だけを切り替えて比較し、4つの差を報告しています。
| 項目 | handle() | cf() で組んだ場合 |
|---|---|---|
| ページが設定したCookie | 送られる | 送られない。セッションも毎回新規になる |
| キャッシュプロバイダー有効時の既定ヘッダー | no-store が付く | 付かない |
| ルートに一致しないパス | 静的アセットへフォールバック | 404ページ |
prerender = true のページを含むビルド | 成功 | 失敗 |
どれも警告なしに静かに起きるうえ、型チェックも通ります。Cookieが落ちる件は、セッションの保存先であるKVバインディングを cf() が配線していたため、保存はされるのにCookieだけ返らないという、気づきにくい壊れ方でした。no-store の件も地味に危険で、アダプターのソースコードにあるコメントによれば、CloudflareのWorkerキャッシュは既定でGETレスポンスを最長2時間キャッシュします。キャッシュの意図を書いていないルートが、知らないうちに共有キャッシュへ乗ることになります。Issueを立てた人の分析では、cf() が13.6.0で書かれた後に handle() 側へ入った改修が、cf() 側には入っていなかったのが原因だそうです。
14.3.0での変更
@astrojs/cloudflare 14.3.0で、これらがまとめて直っています。表の上2つ、CookieとCDNキャッシュの既定値は、新しい finalize() ヘルパーで付けます。Astroのパイプラインが返した Response と、同じ FetchState を渡します。
// src/worker.ts
import { astro, FetchState } from 'astro/fetch';
import { cf, finalize } from '@astrojs/cloudflare/fetch';
export default {
async fetch(request: Request, env: Env, context: ExecutionContext) {
const state = new FetchState(request);
const asset = await cf(state, env, context);
if (asset) return asset;
return finalize(state, await astro(state));
},
};
表の下2つ、静的アセットへのフォールバックとworkerdでのプリレンダリングは、アダプター側の内部変更で直っていて、finalize() を呼ばなくても効きます。アダプターのCHANGELOGには、ルートに一致しないときは静的アセットへフォールバックし、workerd経由のプリレンダリングでは既定のサーバーエントリポイントを使う、とあります。
どの抜けがどちらで直ったかは、この対応表のとおりです。
Honoを使っている場合は、@astrojs/cloudflare/hono の cf() ミドルウェアが、後続のハンドラーの実行後に自動で同じ仕上げをします。finalize() を呼ぶ必要はありません。
// src/worker.ts
import { Hono } from 'hono';
import { actions, middleware, pages, i18n } from 'astro/hono';
import { cf } from '@astrojs/cloudflare/hono';
const app = new Hono<{ Bindings: Env }>();
app.use(cf());
app.use(actions());
app.use(middleware());
app.use(pages());
app.use(i18n());
export default app;
cf() で組んだエントリポイントを使っていて、finalize() を足さずに14.3.0へ上げた場合、CookieとCDNの既定ヘッダーは付かないままです。上げたら忘れずに1行足してください。逆に、handle() に委譲しているプロジェクトや、そもそもカスタムエントリポイントを使っていないプロジェクトには、関係のない変更です。
7.3系で入った修正
CHANGELOGから、実用上影響のある修正を拾っておきます。
インクリメンタルビルドと並列ビルドの両立
7.2の記事で、実験的機能のインクリメンタルスタティックビルドは build.concurrency が1より大きいと無効になる、と書きました。7.3.0でこの制限が外れています。並列レンダリング中も、ページごとに独立したストアでコンテンツエントリと画像変換の依存を記録するようになったためです。キャッシュを効かせるために build.concurrency: 1 へ落としていたプロジェクトは、その回避策を消せます。@astrojs/cloudflare のworkerd経由プリレンダリングでも同じ仕組みが入り、大きなプリレンダリング済みページのシリアライズ負荷も減っています。
並列ビルド時の挙動を7.2までと比べると、こうなります。
なお、2026年9月5日時点の公式ドキュメントの制限一覧には、まだ build.concurrency の制限が書かれています。PRの説明に、この制限はビルド時の警告でしか表に出ていなかったのでドキュメント更新は不要、とあるので、自分は古い記述が残っているだけだと見ています。ただし実際に試すときは、自分のビルドログで警告が消えたことを確かめてください。
メモリキャッシュの Vary: Cookie 対応
memoryCache() は、レスポンスの Vary ヘッダーに挙がっているリクエストヘッダーの値ごとに、別のキャッシュエントリを作ります。ドキュメントによると、これまで Cookie はユーザーごとに違いすぎて実質キャッシュできないという理由で、キーを作るときに無視されていました。しかしそれでは、Cookieの内容で中身が変わるレスポンスが、Cookieを無視したキーで他のユーザーへ配られかねません。7.3.0からは Vary: Cookie と Vary: * を含むレスポンスは保存自体を飛ばし、前述のとおり logger.warn() で理由を出します。
そのほかの修正
- 多数のモジュールから多数のページを生成するサイトで、ビルド性能を改善(7.3.0)
- サーバーアイランドの中でレンダリングしたコンテンツコレクションのエントリから、スタイル、リンク、スクリプトが欠ける問題の修正(7.3.0)
- i18nのフォールバックルートで、ロケールコードが後続のパスセグメントの先頭にも現れるとパスが壊れる問題の修正。
src/pages/en/enterprise.astroにfallback: { es: 'en' }を設定すると/es/esterpriseが生成されていた(7.3.0) astro:assetsを使うプロジェクトが起動もビルドもできなくなる問題の修正(7.3.1)@astrojs/cloudflareで、初回のastro devがクラッシュする問題の修正(14.3.0)
アップグレード前に確認したいこと
- まずは
npx @astrojs/upgradeで7.3.1以降へ上げ、既存のビルドが通ることを確認する。新機能はどれもオプトインなので、ここまでは何も変わらない - Playwrightなどで複数のプレビューサーバーを立てているなら、
webServerのcommandに--ignore-lockと明示的な--portを付ける。AIエージェントから実行する場合はASTRO_PREVIEW_BACKGROUND=0も添える - 画像サービスやキャッシュプロバイダーを自作しているなら、
console.warn()をlogger.warn()へ置き換える。画像サービスのフックを直接呼んでいるコードがあれば、loggerを末尾へ渡す - Cloudflareで
src/worker.tsをcf()で組んでいるなら、@astrojs/cloudflareを14.3.0以降へ上げ、astro(state)の戻り値をfinalize(state, ...)で包む。Honoならcf()ミドルウェアが入っているかを確認するだけでよい - インクリメンタルビルドのために
build.concurrency: 1へ落としていたなら、元の値へ戻して2回続けてビルドし、2回目でキャッシュが効いていることをログで確認する
この5つを上から順に見ていけば、自分に関係のあるものだけ拾えます。
要点
- Astro 7.3は2026年9月3日リリースのマイナーバージョンで、破壊的変更はありません。同日に出た7.3.1が
astro:assetsの起動不能を直しているので、上げるなら7.3.1以降にします。 astro preview --ignore-lockで、ロックファイルを無視してプレビューサーバーを並行起動できます。--backgroundや--forceとは併用できず、AIエージェント環境の自動バックグラウンド化とも衝突するため、その場合はASTRO_PREVIEW_BACKGROUND=0を添えます。- 画像サービスの全フックは末尾引数として、キャッシュプロバイダーの
onRequest()はcontext.loggerとして、Astroのランタイムロガーを受け取ります。設定したログレベルと出力先に従うので、console.warn()から置き換えます。組み込みのSharpとmemoryCache()も同じ経路に移りました。 @astrojs/cloudflare14.3.0のfinalize()は、astro/fetchとcf()で組んだエントリポイントのレスポンスへ、CookieとCDNキャッシュの既定値を付けます。Honoのcf()ミドルウェアは自動で行います。- インクリメンタルビルドは
build.concurrencyが1より大きくても効くようになりました。build.concurrency: 1の回避策は不要です。
参考資料
- Astro 7.3 | Astro(2026年9月3日公開、2026年9月5日参照)
- astro CHANGELOG | withastro/astro(2026年9月5日参照。最新は7.3.1)
- CLI Commands | Astro Docs(2026年9月5日参照)
- Image Service API | Astro Docs(2026年9月5日参照)
- Astro Cache Provider API | Astro Docs(2026年9月5日参照)
- Astro Logger API | Astro Docs(2026年9月5日参照)
- @astrojs/cloudflare | Astro Docs(2026年9月5日参照)
- @astrojs/cloudflare CHANGELOG | withastro/astro(2026年9月5日参照。最新は14.3.0)