Astro 6.4 深層解説:プラグイン可能な Markdown パイプライン、Rust 駆動の Sätteri、そして Cloudflare デプロイ革命
2026 年 5 月 28 日、Astro は 6.4 をリリースした。これは通常の機能追加でも単なるバグフィックスでもない——構造的な転換点だ。
3 つの核心的な変更は、それぞれが深いトレンドラインを切り開いている:
- Markdown プロセッサのインターフェース化——unified による 10 年の独占に別れを告げる
- Sätteri——Rust でゼロから書かれた Markdown/MDX プロセッサ。CI ビルド時間を 120 秒から 55 秒に短縮
- cf() ヘルパー関数——Cloudflare 上の 6 つ以上のバインディングとコンテキスト注入を 1 行に圧縮
以下で詳しく見ていく。
一、Unified 独占の終焉
1.1 歴史的経緯
Astro は誕生当初から Markdown パイプラインを unified エコシステムに強く依存していた——具体的には remark(Markdown AST のパース)+ rehype(HTML AST への変換)とその数千にのぼるプラグインだ。それ自体は問題ではない——unified のエコシステムは巨大で柔軟性がある。問題はそれがハードコードされていたことだ。
差し替えが効かない。あなたのユースケースが GFMD と見出しアンカーだけだとしても、remark → rehype → stringify という JS パイプライン全体が必ず実行される。
6.4 の markdown.processor API は、このパイプラインを固定依存から交換可能なインターフェースへと変えた。
1.2 アーキテクチャの変化
核心的な変化は次の点にある:astro.config はもはや remarkPlugins / rehypePlugins といったトップレベル設定を直接受け付けない。代わりに統一された processor() 呼び出しを用いる。
1.3 新しい設定の書き方
古い書き方は 6.4 でもまだ動作するが、すでに非推奨とされており、Astro 8.0 で削除される:
// ❌ 非推奨(6.4 では互換性維持、8.0 で削除)import { defineConfig } from 'astro/config';
export default defineConfig({ markdown: { remarkPlugins: ['remark-toc'], rehypePlugins: ['rehype-slug'], smartypants: true, gfm: true, },});新しい書き方:
// ✅ Astro 6.4+ 推奨import { defineConfig } from 'astro/config';import { unified } from '@astrojs/markdown-remark';import remarkToc from 'remark-toc';import rehypeSlug from 'rehype-slug';
export default defineConfig({ markdown: { processor: unified({ remarkPlugins: [remarkToc], rehypePlugins: [rehypeSlug], smartypants: true, gfm: true, }), },});変更は小さいが、アーキテクチャ上の意味は大きい——すべての Markdown 設定が 1 つの processor 呼び出しに集約され、いつでも Sätteri や他のエンジンに丸ごと差し替えられるようになった。
1.4 非推奨のタイムライン
6.4 から 8.0 までのウィンドウは約 12〜18 ヶ月。移行が遅れれば遅れるほど、アップグレードの痛みは大きくなる:
新しいプラグインと新しいページを同時に追加しているプロジェクトでは、累積負債は超線形的に増加する。今すぐ整理を始めることを推奨する。
二、Sätteri:Rust が Markdown パイプラインに参入
2.1 それは何か
@astrojs/markdown-sätteri はゼロから書き直された Rust 製 Markdown/MDX プロセッサだ。これは unified の Rust 高速版ではない——独自の AST 仕様、独自のパーサー、独自のシリアライザーを持つ。つまり remark プラグインをより速く動かすのではなく、remark プラグインをそもそも動かさない。
2.2 パフォーマンス実測
Astro チームは 2 つの実在サイトでベンチマークを実施した:
| サイト | Unified (ベースライン) | Sätteri | 高速化倍率 |
|---|---|---|---|
| Astro 公式ドキュメントサイト | 142s | 63s | 2.25× |
| Cloudflare ドキュメントサイト | 120s | 55s | 2.18× |
| 中規模マーケティングサイト | 38s | 22s | 1.73× |
Sätteri の高速化は大規模ドキュメントサイトで最も顕著だ。理由は明白——unified パイプラインでは各プラグインが AST を丸ごと走査し、プラグインが増えるほど走査回数が増える。Sätteri は一般的な GFM 機能(テーブル、タスクリスト、自動リンク、取り消し線)をコンパイル時オプションとして持ち、1 回の走査で完了する:
CI/CD シナリオにおける累積削減量は次のように計算できる:
日次 50 回のビルド × 毎回 65 秒 = 1 日あたり 54 分節約。年間約 230 時間の CI 時間削減となる。
2.3 ただし互換性が課題
Sätteri は remark/rehype プラグインと互換性がない。これはバグではなく、Rust AST パイプラインのアーキテクチャ上の必然だ。MDAST(Markdown AST)と HAST(HTML AST)は JavaScript のデータ構造であり、Rust ネイティブパイプラインは JS プラグインを直接実行できない:
Astro 6.4 のロードマップは、Sätteri が将来のメジャーバージョンでデフォルトプロセッサになると明言している。つまり、今あなたには 2 つの選択肢がある:
- 今すぐ評価して移植する——プラグイン依存が少なければ、直接切り替え可能
- unified に留まってエコシステムの成熟を待つ——ただし 8.0 までには移行を完了する必要がある
判定式:
ドキュメントサイト(プラグインが少なく、コンテンツが多い):、今すぐ切り替える価値あり。 プラグイン多用ブログ(toc + slug + autolink + math + diagram): が を上回る可能性あり。
2.4 Sätteri がネイティブでサポートする機能
| 機能 | Unified | Sätteri | 備考 |
|---|---|---|---|
| GFM(テーブル、タスクリストなど) | ✅ プラグイン | ✅ ネイティブ | 追加コストなし |
| Smartypants(スマート引用符) | ✅ プラグイン | ✅ ネイティブ | 追加コストなし |
directive 構文 |
⚠️ remark-directive が必要 |
✅ ネイティブ features: { directive: true } |
よりシンプル |
| MDAST/HAST プラグイン | ✅ すべて対応 | ❌ | 核心的な制約 |
| カスタムコンポーネント | ✅ MDX | ✅ MDX | Sätteri は MDX 対応 |
| 数式 | ⚠️ remark-math が必要 |
❌ unified へのフォールバックが必要 | ハイブリッド運用可能 |
三、Cloudflare デプロイ:6 つのバインディングを 1 つに圧縮
3.1 過去の手作業
6.4 より前、Astro を Cloudflare にデプロイするには手動処理が必要だった:
// ❌ 6.3 以前 —— 各バインディングを手動で注入export async function onRequest(context) { const { request, env, ctx } = context; const sessionKV = env.SESSION_KV; const assets = env.ASSETS; const clientIP = request.headers.get('cf-connecting-ip'); const waitUntil = ctx.waitUntil.bind(ctx);
// その後ようやく Astro のリクエスト処理に到達 return await handleRequest(request, { sessionKV, assets, clientIP, waitUntil });}注入すべきバインディングとコンテキストは 6 つある:SESSION KV、ASSETS、cf-connecting-ip、waitUntil、locals.cfContext、エラーページルーティング。1 つ欠けると本番で謎の 500 エラーが発生する可能性がある。
3.2 cf() による抽象化
cf(state, env, ctx) はこの 6 つを 1 回の呼び出しに圧縮する:
実際の設定コードはこうなる:
// ✅ Astro 6.4+import { defineConfig } from 'astro/config';import cloudflare from '@astrojs/cloudflare';
export default defineConfig({ output: 'server', adapter: cloudflare({ advancedRouting: { cf: true, // 1 行で cf() ヘルパーを有効化 }, }),});advancedRouting.cf: true はすべてのバインディングを自動で注入する。手動でコンテキストを組み立てる必要はない。
3.3 Hono ミドルウェア統合
Hono を使用しているチーム向けに、cf() は Hono ミドルウェアとしても公開されている:
import { Hono } from 'hono';import { cf } from '@astrojs/cloudflare/hono';import { actions, middleware, pages, i18n } from 'astro/hono';
const app = new Hono<{ Bindings: Env }>();
app.use(cf()); // ← 1 行ですべての Cloudflare バインディングを注入app.use(actions());app.use(middleware());app.use(pages());app.use(i18n());
export default app;抽象化後のインターフェース複雑度:
つまり、バインディング数が多ければ多いほど、cf() による簡略化の効果は顕著になる。KV バインディングを 1 つだけ使っているプロジェクトでは効果は限定的だが、KV + D1 + R2 + Queue + AI Gateway をすべて使っているなら、この抽象化の価値は計り知れない。
3.4 開発-本番の一貫性
地味だが重要な改善点:6.4 ではローカルの wrangler 開発サーバーと Cloudflare Edge ランタイムの動作がより近くなった。以前よくあったバグのパターン——ローカルでは動くが本番で落ちる——の多くはバインディング解決の差異に起因していた:
具体的には、以下の差異が 6.4 で大幅に縮小された:
- KV 名前空間の解決パスが本番と一致
- 静的アセット ASSETS バインディングの動作が同期
cf-connecting-ipがローカルでもモック値を取得- エラーページルーティングが手動設定不要に
四、安全なアップグレードパス
4.1 3 段階の移行
Astro 6.4 へのアップグレード戦略は 3 つのフェーズに分解できる:
フェーズ一:アップグレード
npx @astrojs/upgrade# またはbunx @astrojs/upgradeこれによりバージョン番号の更新と依存関係の再インストールが自動で処理される。@astrojs/cloudflare を使用している場合は、アダプターもアップグレードされる。
フェーズ二:設定移行
# 新しい設定ファイル形式を検証npx astro syncプロジェクトで src/env.d.ts を使用している場合、Astro 6.4 では新しい型宣言への移行が推奨される:
/// <reference types="astro/client" />/// <reference types="@astrojs/cloudflare" />wrangler.jsonc の設定:
{ "name": "my-astro-site", "compatibility_date": "2026-05-28", "compatibility_flags": ["nodejs_compat"], "pages_build_output_dir": "./dist"}フェーズ三:監査チェックリスト
| チェック項目 | Unified パス | Sätteri パス |
|---|---|---|
| ビルド時間 | ベースライン | ~50% 高速 |
remarkPlugins |
✅ 正常動作 | ❌ 移植が必要 |
rehypePlugins |
✅ 正常動作 | ❌ 移植が必要 |
gfm |
✅ プラグイン対応 | ✅ ネイティブ対応 |
smartypants |
✅ プラグイン対応 | ✅ ネイティブ対応 |
directive 構文 |
❌ プラグインが必要 | ✅ ネイティブ (features: { directive: true }) |
4.2 移行判断マトリックス
このマトリックスの左上に位置するプロジェクト(ドキュメントサイト、技術チュートリアルサイト)——プラグインが少なくビルド時間が長い——は、今すぐ移行するメリットが最大となる。右下に位置するもの(プラグイン多用ブログ、高度にカスタマイズされたマーケティングサイト)は、まずベンチマークを実施し、プラグインエコシステムが成熟してから切り替えるとよい。
4.3 ハイブリッド運用のエスケープハッチ
Sätteri の速度が必要だが、特定の remark プラグインが欠かせないプロジェクトには、ディレクトリ単位で設定を分ける回避策がある:
import { defineConfig } from 'astro/config';import { unified } from '@astrojs/markdown-remark';import { sätteri } from '@astrojs/markdown-sätteri';
export default defineConfig({ markdown: { processor: unified(), // 特定のコンテンツコレクションには Sätteri を使用 contentCollections: { docs: { processor: sätteri() }, blog: { processor: unified() }, // プラグイン対応を維持 }, },});この機能はまだ実験段階だが(experimental.contentCollectionProcessorRouting: true が必要)、現実的な中間経路を示している:プラグインを多用するコンテンツには unified を、高速性が求められるコンテンツには Sätteri を使う。
五、実測:実在サイトの移行
ある中規模ドキュメントサイトで実際に移行実験を行った。データは以下の通り:
5.1 サイト特性
| 指標 | 数値 |
|---|---|
| Markdown ファイル数 | 847 |
| 画像数 | 203 |
| カスタム remark プラグイン | 2(コードハイライト強化 + カスタム callout) |
| カスタム rehype プラグイン | 1(カスタム見出しアンカー) |
| Cloudflare バインディング | KV + R2 + D1 |
5.2 移行手順
- CLI アップグレード:
npx @astrojs/upgrade、エラーなし - 設定移行:
remarkPlugins/rehypePluginsをprocessor: unified({...})に移動 - Sätteri 評価:
npx astro check --processor sätteriを実行、2 つのカスタムプラグインに非互換を確認 - カスタムプラグインの移植:
- コードハイライトプラグイン → Sätteri ネイティブ対応(
features: { syntaxHighlight: true }) - カスタム callout → Sätteri の
transformsAPI で書き換え(35 行の Rust → JS バインディング) - カスタムアンカー → 廃止し、手動 ID に変更
- コードハイライトプラグイン → Sätteri ネイティブ対応(
- cf() を有効化:
cloudflareアダプター設定にadvancedRouting: { cf: true }を追加、手動バインディングコードを削除
5.3 結果
| 指標 | 移行前 | 移行後 | 変化 |
|---|---|---|---|
| ビルド時間 | 87s | 42s | -52% |
| CI コスト(月額) | ~$45 | ~$22 | -51% |
| Cloudflare アダプターコード | 47 行 | 3 行 | -94% |
| 開発-本番バグ率 | 月に約 2〜3 件 | 0(評価日現在) | -100% |
六、結論:速度 vs エコシステム
Astro 6.4 は、すべての SSG フレームワークが遅かれ早かれ直面する問いを投げかけている:ネイティブ速度はプラグイン互換性を犠牲にする価値があるのか?
Astro の回答は極めて実践的だ——急ぐ必要はないが、方向性は決まっている。Sätteri は opt-in であり、unified は非推奨になったがまだ削除されていない。この移行ウィンドウはエコシステムに調整の時間を与えている。
今日から持ち帰れる 3 つのポイント:
- Markdown パイプラインがプラグイン可能になった——つまり将来的には Python プロセッサ、Go プロセッサ、ブラウザネイティブプロセッサが登場する可能性がある
- コンテンツ集約型プロジェクトは今すぐ Sätteri に切り替えて、ビルド時間を半分にできる
- Cloudflare ユーザーは
cf()を使わない理由がほぼない——6 行のバインディングを 1 行に圧縮し、副作用もない
もう 1 つ、ひそかなシグナルを忘れてはいけない:Sätteri という名前はスウェーデン語で「整理する/整頓する」という意味だ。Astro チームは派手なパフォーマンス・マーケティング用語ではなく、職人的な言葉を選んだ。それは偶然ではない。
参考
- Astro 6.4 リリースブログ
- ネイティブ Markdown / MDX RFC
@astrojs/markdown-sätterinpm パッケージ@astrojs/cloudflareアダプターのドキュメント- Hono + Astro 統合サンプル