jpskill.com
🛠️ 開発・MCP コミュニティ

web-meta-framework-astro

Astroは、コンテンツを重視したWebサイト構築フレームワークで、部分的なインタラクティブ性、ファイルベースのルーティング、柔軟なレンダリング方式、画面遷移、多様なフレームワークのコンポーネント利用をサポートするSkill。

📜 元の英語説明(参考)

Astro content-first framework - islands architecture, content collections, file-based routing, SSR/SSG hybrid rendering, View Transitions, server islands, multi-framework component support

🇯🇵 日本人クリエイター向け解説

一言でいうと

Astroは、コンテンツを重視したWebサイト構築フレームワークで、部分的なインタラクティブ性、ファイルベースのルーティング、柔軟なレンダリング方式、画面遷移、多様なフレームワークのコンポーネント利用をサポートするSkill。

※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。

⚡ おすすめ: コマンド1行でインストール(60秒)

下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。

🍎 Mac / 🐧 Linux
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o web-meta-framework-astro.zip https://jpskill.com/download/10290.zip && unzip -o web-meta-framework-astro.zip && rm web-meta-framework-astro.zip
🪟 Windows (PowerShell)
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/10290.zip -OutFile "$d\web-meta-framework-astro.zip"; Expand-Archive "$d\web-meta-framework-astro.zip" -DestinationPath $d -Force; ri "$d\web-meta-framework-astro.zip"

完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。

💾 手動でダウンロードしたい(コマンドが難しい人向け)
  1. 1. 下の青いボタンを押して web-meta-framework-astro.zip をダウンロード
  2. 2. ZIPファイルをダブルクリックで解凍 → web-meta-framework-astro フォルダができる
  3. 3. そのフォルダを C:\Users\あなたの名前\.claude\skills\(Win)または ~/.claude/skills/(Mac)へ移動
  4. 4. Claude Code を再起動

⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。

🎯 このSkillでできること

下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。

📦 インストール方法 (3ステップ)

  1. 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
  2. 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
  3. 3. 展開してできたフォルダを、ホームフォルダの .claude/skills/ に置く
    • · macOS / Linux: ~/.claude/skills/
    • · Windows: %USERPROFILE%\.claude\skills\

Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。

詳しい使い方ガイドを見る →
最終更新
2026-05-18
取得日時
2026-05-18
同梱ファイル
1

📖 Skill本文(日本語訳)

※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。

Astro フレームワークのパターン

クイックガイド: Astro はデフォルトでページを静的な HTML にレンダリングし、クライアント側の JavaScript は一切使用しません。すべての静的コンテンツには .astro コンポーネントを使用し、インタラクティブなフレームワークコンポーネント (React/Vue/Svelte) にのみ client:* ディレクティブを追加してください。型安全な構造化コンテンツにはコンテンツコレクションを使用してください。ページごとに静的 (デフォルト) レンダリングとオンデマンド (SSR) レンダリングを選択するには、export const prerender を使用します。


<critical_requirements>

重要: この Skill を使用する前に

すべてのコードは CLAUDE.md のプロジェクト規約に従う必要があります (kebab-case, 名前付きエクスポート, インポート順, import type, 名前付き定数)

(デフォルトではページを静的にする必要があります - ページがリクエスト時のデータを本当に必要とする場合にのみ export const prerender = false を追加してください)

*(インタラクティブ性が必要なフレームワークコンポーネントには `client:` ディレクティブを使用する必要があります - ディレクティブがない場合、コンポーネントは JavaScript を一切含まない静的な HTML にレンダリングされます)**

(型安全な frontmatter のために、Zod スキーマを使用して src/content.config.ts にコンテンツコレクションを定義する必要があります)

(View Transitions には astro:transitions<ClientRouter /> を使用する必要があります - 古い <ViewTransitions /> コンポーネントは Astro 6 で削除されました)

(オンデマンドレンダリングを使用する前に、サーバーアダプター (@astrojs/node, @astrojs/vercel など) をインストールする必要があります)

(静的モードの動的ルートには getStaticPaths() を使用する必要があります - オンデマンド (SSR) ルートには必要ありません)

</critical_requirements>


自動検出: Astro, .astro ファイル, astro.config, islands architecture, client:load, client:visible, client:idle, client:only, client:media, server:defer, content collections, defineCollection, defineLiveCollection, getCollection, getLiveCollection, getEntry, getLiveEntry, render, astro:content, astro:transitions, ClientRouter, getStaticPaths, Astro.props, Astro.params, Astro.cookies, Astro.redirect, prerender, astro add, @astrojs/react, @astrojs/vue, @astrojs/svelte, Starlight

使用する場面:

  • コンテンツ主導のウェブサイトの構築 (ブログ、ドキュメント、マーケティング、ポートフォリオ)
  • ほとんどのページが静的で、選択的なインタラクティブ性を持つサイト (アイランド)
  • 構造化された Markdown/MDX/YAML コンテンツにコンテンツコレクションを使用するプロジェクト
  • React、Vue、Svelte、または Solid コンポーネントを混在させるマルチフレームワークプロジェクト
  • ハイブリッドレンダリングが必要なサイト (静的ページ + 一部のサーバーレンダリングページ)

使用しない場面:

  • 高度にインタラクティブなウェブアプリケーション (ダッシュボード、リアルタイムコラボレーション) - フルスタック SSR フレームワークまたは SPA を使用してください
  • すべてのページでユーザー認証と動的データが必要なアプリ - フルスタック SSR フレームワークを使用してください
  • React Server Components または Server Actions が必要なプロジェクト - React SSR フレームワークを使用してください

カバーする主要なパターン:

  • Astro コンポーネントの構文 (.astro ファイル、frontmatter、テンプレート式、スロット)
  • アイランドアーキテクチャ (クライアントディレクティブ、サーバーアイランド、選択的なハイドレーション)
  • コンテンツコレクション (スキーマ、クエリ、レンダリング、参照、ライブコレクション)
  • ファイルベースルーティング (静的ルート、動的ルート、レストパラメータ、ページネーション)
  • レンダリングモード (静的、オンデマンド/SSR、prerender 制御によるハイブリッド)
  • View Transitions (ClientRouter, transition ディレクティブ, 状態の永続化)
  • フレームワーク統合 (React、Vue、Svelte、Solid アイランド)

詳細なリソース:

  • 意思決定フレームワークとアンチパターンについては、reference.md を参照してください

コアパターン:

  • examples/core.md - Astro コンポーネント、props、スロット、式、レイアウト
  • examples/islands.md - クライアントディレクティブ、サーバーアイランド、マルチフレームワークアイランド
  • examples/content.md - コンテンツコレクション、スキーマ、クエリ、レンダリング
  • examples/routing.md - ファイルベースルーティング、動的ルート、SSR/SSG モード
  • examples/integrations.md - React/Vue/Svelte アイランド、View Transitions

<philosophy>

哲学

Astro は、デフォルトで JavaScript を一切送信しない コンテンツファーストのウェブフレームワーク です。Astro は、ページのほとんどが高速な静的 HTML であり、必要な場合にのみハイドレーションされる JavaScript の小さなインタラクティブな「アイランド」である アイランドアーキテクチャ を先駆的に開発しました。

コア原則:

  1. コンテンツファースト - コンテンツ主導のサイト (ブログ、ドキュメント、マーケティング、e コマース) に最適化
  2. デフォルトで JavaScript はゼロ - コンポーネントは明示的にハイドレーションされない限り、静的な HTML にレンダリングされます
  3. アイランドアーキテクチャ - インタラクティブなコンポーネントは独立してハイドレーションされ、JavaScript のペイロードを削減します
  4. UI に依存しない - React、Vue、Svelte、Solid、Preact、またはプレーンな Astro コンポーネントを使用します
  5. ファイルベースルーティング - src/pages/ ディレクトリ構造は URL に直接マッピングされます
  6. 型安全なコンテンツ - Zod スキーマを使用したコンテンツコレクションは、構造を強制し、TypeScript 型を提供します
  7. ハイブリッドレンダリング - 静的 (SSG) ページとオンデマンド (SSR) ページを同じプロジェクトで混在させます

Astro を使用する場面:

  • コンテンツ主導のウェブサイト (ブログ、ドキュメント、ポートフォリオ、マーケティング)
  • ほとんどが静的コンテンツで、時折インタラクティブ性があるサイト
  • ドキュメントサイト (Starlight 統合)
  • インタラクティブなカートを備えた e コマース製品ページ
  • チームが異なる UI ライブラリを使用するマルチフレームワークプロジェクト

Astro を使用しない場面:

  • 完全にインタラクティブなウェブアプリケーション (フルスタック SSR フレームワークまたは SPA を使用してください)
  • リアルタイムのコラボレーションアプリ (WebSocket サポートを備えた専用の SPA を使用してください)
  • React Server Components または Server Actions が必要なプロジェクト (React SSR フレームワークを使用してください)

</philosophy>


<patterns>

コアパターン

パターン 1: Astro コンポーネントの構造

Astro コンポーネント (.astro ファイル) には、frontmatter スクリプトブロック (--- フェンスの間) と HTML テンプレートの 2 つの部分があります。

コンポーネントの構造

---
// コンポーネントスクリプト (frontmatter) - サーバーでのみ実行されます
import Layout from "../layouts/Layout.astro";
import { getCollection } from "astro:content";

// Astro.props を介してアクセスされる Props
interface Props {
  title: string;
  description?: string;
}

const { title, description = "Default description" } = Astro.props;

// サーバー側のデータ
📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開

Astro Framework Patterns

Quick Guide: Astro renders pages to static HTML by default with zero client-side JavaScript. Use .astro components for all static content, add client:* directives only on interactive framework components (React/Vue/Svelte). Use content collections for type-safe structured content. Choose between static (default) and on-demand (SSR) rendering per-page with export const prerender.


<critical_requirements>

CRITICAL: Before Using This Skill

All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering, import type, named constants)

(You MUST keep pages static by default - only add export const prerender = false when the page genuinely needs request-time data)

*(You MUST use `client:` directives on framework components that need interactivity - without a directive, components render to static HTML with zero JavaScript)**

(You MUST define content collections in src/content.config.ts with Zod schemas for type-safe frontmatter)

(You MUST use <ClientRouter /> from astro:transitions for View Transitions - the old <ViewTransitions /> component is removed in Astro 6)

(You MUST install a server adapter (@astrojs/node, @astrojs/vercel, etc.) before using on-demand rendering)

(You MUST use getStaticPaths() for dynamic routes in static mode - it is not needed for on-demand (SSR) routes)

</critical_requirements>


Auto-detection: Astro, .astro files, astro.config, islands architecture, client:load, client:visible, client:idle, client:only, client:media, server:defer, content collections, defineCollection, defineLiveCollection, getCollection, getLiveCollection, getEntry, getLiveEntry, render, astro:content, astro:transitions, ClientRouter, getStaticPaths, Astro.props, Astro.params, Astro.cookies, Astro.redirect, prerender, astro add, @astrojs/react, @astrojs/vue, @astrojs/svelte, Starlight

When to use:

  • Building content-driven websites (blogs, docs, marketing, portfolios)
  • Sites where most pages are static with selective interactivity (islands)
  • Projects using content collections for structured Markdown/MDX/YAML content
  • Multi-framework projects mixing React, Vue, Svelte, or Solid components
  • Sites needing hybrid rendering (static pages + some server-rendered pages)

When NOT to use:

  • Highly interactive web applications (dashboards, real-time collaboration) - use a full-stack SSR framework or SPA
  • Apps where every page requires user authentication and dynamic data - use a full-stack SSR framework
  • Projects that need React Server Components or Server Actions - use a React SSR framework

Key patterns covered:

  • Astro component syntax (.astro files, frontmatter, template expressions, slots)
  • Islands architecture (client directives, server islands, selective hydration)
  • Content collections (schemas, querying, rendering, references, live collections)
  • File-based routing (static routes, dynamic routes, rest parameters, pagination)
  • Rendering modes (static, on-demand/SSR, hybrid with prerender control)
  • View Transitions (ClientRouter, transition directives, persist state)
  • Framework integrations (React, Vue, Svelte, Solid islands)

Detailed Resources:

  • For decision frameworks and anti-patterns, see reference.md

Core patterns:


<philosophy>

Philosophy

Astro is a content-first web framework that ships zero JavaScript by default. It pioneered the islands architecture where most of the page is fast static HTML, with small interactive "islands" of JavaScript hydrated only where needed.

Core principles:

  1. Content-first - Optimized for content-driven sites (blogs, docs, marketing, e-commerce)
  2. Zero JS by default - Components render to static HTML unless explicitly hydrated
  3. Islands architecture - Interactive components hydrate independently, reducing JavaScript payloads
  4. UI-agnostic - Use React, Vue, Svelte, Solid, Preact, or plain Astro components
  5. File-based routing - src/pages/ directory structure maps directly to URLs
  6. Type-safe content - Content collections with Zod schemas enforce structure and provide TypeScript types
  7. Hybrid rendering - Mix static (SSG) and on-demand (SSR) pages in the same project

When to use Astro:

  • Content-driven websites (blogs, documentation, portfolios, marketing)
  • Sites with mostly static content and occasional interactivity
  • Documentation sites (Starlight integration)
  • E-commerce product pages with interactive carts
  • Multi-framework projects where teams use different UI libraries

When NOT to use Astro:

  • Fully interactive web applications (use a full-stack SSR framework or SPA)
  • Real-time collaborative apps (use a dedicated SPA with WebSocket support)
  • Projects requiring React Server Components or Server Actions (use a React SSR framework)

</philosophy>


<patterns>

Core Patterns

Pattern 1: Astro Component Structure

Astro components (.astro files) have two parts: a frontmatter script block (between --- fences) and an HTML template.

Component Anatomy

---
// Component Script (frontmatter) - runs on the server only
import Layout from "../layouts/Layout.astro";
import { getCollection } from "astro:content";

// Props accessed via Astro.props
interface Props {
  title: string;
  description?: string;
}

const { title, description = "Default description" } = Astro.props;

// Server-side data fetching
const posts = await getCollection("blog");
---

<!-- Component Template - HTML with expressions -->
<Layout title={title}>
  <h1>{title}</h1>
  <p>{description}</p>

  <ul>
    {posts.map((post) => (
      <li>
        <a href={`/blog/${post.id}`}>{post.data.title}</a>
      </li>
    ))}
  </ul>
</Layout>

<style>
  /* Scoped to this component by default */
  h1 {
    color: navy;
    font-size: 2rem;
  }
</style>

Why good: Frontmatter runs server-only (no JavaScript shipped), type-safe props with interface, scoped styles prevent leakage, expressions use JSX-like syntax


Pattern 2: Slots for Composition

Slots allow parent components to inject content into child component templates.

Default and Named Slots

---
// src/components/Card.astro
interface Props {
  title: string;
}

const { title } = Astro.props;
---

<article class="card">
  <header>
    <slot name="header">
      <h2>{title}</h2>
    </slot>
  </header>

  <div class="body">
    <slot />  <!-- Default slot -->
  </div>

  <footer>
    <slot name="footer">
      <p>Default footer</p>
    </slot>
  </footer>
</article>
---
// Usage in a page
import Card from "../components/Card.astro";
---

<Card title="My Card">
  <span slot="header"><h2>Custom Header</h2></span>

  <p>This goes in the default slot.</p>

  <div slot="footer">
    <a href="/more">Read more</a>
  </div>
</Card>

Why good: Named slots provide flexible composition, fallback content renders when no slot content is provided, matches Web Component slot semantics


Pattern 3: Layouts

Layouts are Astro components that wrap page content with shared UI (header, footer, navigation).

Base Layout with Metadata

---
// src/layouts/BaseLayout.astro
interface Props {
  title: string;
  description?: string;
}

const { title, description = "My Astro Site" } = Astro.props;
---

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content={description} />
    <title>{title}</title>
  </head>
  <body>
    <nav>
      <a href="/">Home</a>
      <a href="/blog">Blog</a>
      <a href="/about">About</a>
    </nav>

    <main>
      <slot />
    </main>

    <footer>
      <p>&copy; {new Date().getFullYear()} My Site</p>
    </footer>
  </body>
</html>
---
// src/pages/about.astro
import BaseLayout from "../layouts/BaseLayout.astro";
---

<BaseLayout title="About Us" description="Learn about our team">
  <h1>About Us</h1>
  <p>We build great things with Astro.</p>
</BaseLayout>

Why good: Shared layout reduces duplication, metadata props ensure SEO per-page, slot injects page content


Pattern 4: Islands Architecture (Client Directives)

By default, framework components (React, Vue, Svelte) render to static HTML. Add a client:* directive to hydrate them as interactive islands.

Client Directive Reference

Directive When it hydrates Use for
client:load Immediately on page load Critical interactive UI
client:idle When browser is idle Lower-priority interactivity
client:visible When component scrolls into viewport Below-the-fold content
client:media When media query matches Responsive interactivity
client:only Skips server render, client-only Browser-dependent components
---
// src/pages/index.astro
import Header from "../components/Header.astro"; // Static - no JS
import SearchBar from "../components/SearchBar"; // React component
import Newsletter from "../components/Newsletter"; // React component
import Comments from "../components/Comments"; // React component
import Analytics from "../components/Analytics"; // React component
---

<Header />

<!-- Hydrate immediately - user interacts with search right away -->
<SearchBar client:load />

<!-- Hydrate when browser is idle - not urgent -->
<Newsletter client:idle />

<!-- Hydrate only when scrolled into view -->
<Comments client:visible />

<!-- Hydrate only on mobile screens -->
<Analytics client:media="(max-width: 768px)" />

Why good: Only interactive components ship JavaScript, hydration is deferred to optimal timing, static components render as zero-JS HTML

Server Islands

Server islands defer rendering of dynamic content on the server, allowing static shell to cache while dynamic parts render per-request.

---
// src/pages/product.astro
import ProductInfo from "../components/ProductInfo.astro"; // Static
import UserReviews from "../components/UserReviews.astro"; // Dynamic
---

<!-- Static product info - cached -->
<ProductInfo product={product} />

<!-- Server island - rendered per-request, placeholder shown while loading -->
<UserReviews server:defer>
  <div slot="fallback">Loading reviews...</div>
</UserReviews>

Why good: Static page shell caches and serves instantly, dynamic portions render per-request without blocking the page, fallback content prevents layout shift


Pattern 5: Content Collections

Content collections provide type-safe management of structured content (blog posts, docs, product data).

Defining Collections

// src/content.config.ts
import { defineCollection } from "astro:content";
import { glob, file } from "astro/loaders";
import { z } from "astro/zod";

const blog = defineCollection({
  loader: glob({ pattern: "**/*.md", base: "./src/content/blog" }),
  schema: z.object({
    title: z.string(),
    description: z.string(),
    pubDate: z.coerce.date(),
    updatedDate: z.coerce.date().optional(),
    heroImage: z.string().optional(),
    draft: z.boolean().default(false),
    tags: z.array(z.string()).default([]),
  }),
});

const authors = defineCollection({
  loader: file("src/data/authors.json"),
  schema: z.object({
    name: z.string(),
    bio: z.string(),
    avatar: z.string(),
  }),
});

export const collections = { blog, authors };

Querying and Rendering Collections

---
// src/pages/blog/index.astro
import { getCollection } from "astro:content";
import BaseLayout from "../../layouts/BaseLayout.astro";

const allPosts = await getCollection("blog", ({ data }) => {
  return data.draft !== true; // Filter out drafts
});

// Sort by date descending
const sortedPosts = allPosts.sort(
  (a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf()
);
---

<BaseLayout title="Blog">
  <h1>Blog</h1>
  <ul>
    {sortedPosts.map((post) => (
      <li>
        <a href={`/blog/${post.id}`}>
          <h2>{post.data.title}</h2>
          <time datetime={post.data.pubDate.toISOString()}>
            {post.data.pubDate.toLocaleDateString()}
          </time>
        </a>
      </li>
    ))}
  </ul>
</BaseLayout>
---
// src/pages/blog/[id].astro
import { getCollection, getEntry, render } from "astro:content";
import BaseLayout from "../../layouts/BaseLayout.astro";

export async function getStaticPaths() {
  const posts = await getCollection("blog");
  return posts.map((post) => ({
    params: { id: post.id },
    props: { post },
  }));
}

const { post } = Astro.props;
const { Content } = await render(post);
---

<BaseLayout title={post.data.title}>
  <article>
    <h1>{post.data.title}</h1>
    <time datetime={post.data.pubDate.toISOString()}>
      {post.data.pubDate.toLocaleDateString()}
    </time>
    <Content />
  </article>
</BaseLayout>

Why good: Zod schemas validate frontmatter at build time, TypeScript types are auto-generated, querying with filters is type-safe, render() converts Markdown to a component

Live Collections (Astro 6+)

For data that changes frequently and needs to be fresh on every request, use defineLiveCollection in a separate src/live.config.ts file (not src/content.config.ts). Query with getLiveCollection() and getLiveEntry() instead of getCollection(). Requires SSR (prerender = false). See examples/content.md for full examples.


Pattern 6: File-Based Routing

The src/pages/ directory structure directly maps to URL paths.

Static Routes

src/pages/
├── index.astro          → /
├── about.astro          → /about
├── blog/
│   ├── index.astro      → /blog
│   └── [id].astro       → /blog/:id (dynamic)
├── docs/
│   └── [...slug].astro  → /docs/* (rest parameter)
└── _helpers.ts          → excluded (underscore prefix)

Dynamic Routes with getStaticPaths

---
// src/pages/tags/[tag].astro
import { getCollection } from "astro:content";

export async function getStaticPaths() {
  const posts = await getCollection("blog");
  const tags = [...new Set(posts.flatMap((post) => post.data.tags))];

  return tags.map((tag) => ({
    params: { tag },
    props: {
      posts: posts.filter((post) => post.data.tags.includes(tag)),
    },
  }));
}

const { tag } = Astro.params;
const { posts } = Astro.props;
---

<h1>Posts tagged: {tag}</h1>
<ul>
  {posts.map((post) => (
    <li><a href={`/blog/${post.id}`}>{post.data.title}</a></li>
  ))}
</ul>

Rest Parameters

---
// src/pages/docs/[...slug].astro
export async function getStaticPaths() {
  return [
    { params: { slug: "getting-started" } },
    { params: { slug: "guides/installation" } },
    { params: { slug: "api/reference" } },
    { params: { slug: undefined } }, // matches /docs
  ];
}

const { slug } = Astro.params;
---

<h1>Docs: {slug ?? "Index"}</h1>

Why good: File structure mirrors URL structure, dynamic params are type-safe via getStaticPaths, rest parameters handle arbitrary depth


Pattern 7: On-Demand Rendering (SSR)

Opt individual pages into server-side rendering while keeping the rest static.

Per-Page SSR

---
// src/pages/dashboard.astro
export const prerender = false; // Render on every request

const cookie = Astro.cookies.get("session");
if (!cookie) {
  return Astro.redirect("/login");
}

const user = await getUserFromSession(cookie.value);
---

<h1>Welcome, {user.name}</h1>

Server Output Mode

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

export default defineConfig({
  output: "server", // All pages server-rendered by default
  adapter: node({ mode: "standalone" }),
});
---
// src/pages/about.astro
export const prerender = true; // Opt this page back to static
---

<h1>About Us</h1>

API Endpoints

// src/pages/api/search.ts
export const prerender = false;

import type { APIRoute } from "astro";

export const GET: APIRoute = async ({ url }) => {
  const query = url.searchParams.get("q");
  if (!query) {
    return new Response(JSON.stringify({ error: "Missing query" }), {
      status: 400,
      headers: { "Content-Type": "application/json" },
    });
  }

  const results = await searchDatabase(query);
  return new Response(JSON.stringify(results), {
    headers: { "Content-Type": "application/json" },
  });
};

Why good: Static by default for performance, opt into SSR per-page as needed, API endpoints support full request/response control


Pattern 8: View Transitions

Astro provides smooth page transitions using the browser's View Transition API via the <ClientRouter /> component.

Enabling View Transitions

---
// src/layouts/BaseLayout.astro
import { ClientRouter } from "astro:transitions";
---

<html lang="en">
  <head>
    <ClientRouter />
  </head>
  <body>
    <slot />
  </body>
</html>

Transition Directives

---
// src/pages/blog/[id].astro
---

<!-- Name pairs elements across pages for smooth morphing -->
<img
  src={post.data.heroImage}
  transition:name={`hero-${post.id}`}
  transition:animate="slide"
/>

<h1 transition:name={`title-${post.id}`}>
  {post.data.title}
</h1>

<!-- Persist interactive elements across navigations -->
<audio controls transition:persist>
  <source src="/music.mp3" type="audio/mp3" />
</audio>

Why good: Smooth transitions between pages without SPA framework, paired elements morph naturally, persistent elements maintain state across navigation

</patterns>


<red_flags>

RED FLAGS

High Priority Issues:

  • Adding client:load to every component - Defeats islands architecture; only hydrate components that need interactivity
  • Using framework components for static content - Use .astro components for zero-JS static HTML
  • Missing getStaticPaths() on dynamic routes in static mode - Build will fail
  • Using <ViewTransitions /> - Removed in Astro 6; use <ClientRouter /> from astro:transitions
  • No server adapter with prerender = false - On-demand rendering requires an adapter

Medium Priority Issues:

  • Fetching data in <script> tags instead of frontmatter - Frontmatter runs server-side; use it for data fetching
  • Using client:only when client:load would work - client:only skips SSR, hurting SEO
  • Missing Zod schema on content collections - Loses type safety and build-time validation
  • Using output: 'server' for mostly static sites - Default static mode with per-page SSR opt-in is more performant

Gotchas & Edge Cases:

  • Styles in .astro are scoped by default - Use <style is:global> or :global() selector for global styles
  • client:visible uses IntersectionObserver - Component won't hydrate if always off-screen
  • Astro.redirect() only works in on-demand rendered pages - Static pages cannot redirect at request time
  • Multiple framework islands share no state - Each island is independent; use nanostores for cross-island communication
  • transition:persist requires matching transition:name - Elements must have the same name on both pages
  • Astro 6 requires Node.js 22.12.0+ - Earlier Node versions are not supported
  • Astro.glob() removed in Astro 6 - Use import.meta.glob() instead
  • z from astro:content removed in Astro 6 - Import z from astro/zod instead
  • Astro 6 uses Zod 4 - Some Zod 3 patterns changed (e.g., z.string().email() becomes z.email())
  • getStaticPaths() params must be strings - Number params are no longer allowed in Astro 6
  • Live collections use src/live.config.ts - Not src/content.config.ts (separate config file)
  • import.meta.env values are inlined at build time in Astro 6 - Use process.env for runtime secrets in live collections and SSR code

For complete anti-patterns with code examples, see reference.md.

</red_flags>


<integration>

Integration Guide

Astro is the top-level framework. It handles routing, rendering, and content management. UI framework components (React, Vue, Svelte) are used as islands within Astro pages.

Adding framework support:

# Add framework support via CLI
npx astro add react
npx astro add vue

# Add multiple integrations at once
npx astro add react sitemap

Key integrations:

  • UI Frameworks - React, Vue, Svelte, Solid used as interactive islands within Astro pages
  • MDX - Via @astrojs/mdx for components in Markdown
  • Starlight - Astro's documentation theme, built on content collections

Deployment adapters:

  • @astrojs/vercel - Vercel deployment with edge/serverless
  • @astrojs/netlify - Netlify Functions/Edge
  • @astrojs/cloudflare - Cloudflare Workers/Pages
  • @astrojs/node - Self-hosted Node.js server

Does NOT replace:

  • Full-stack SSR frameworks for highly interactive, full-stack React applications
  • SPA frameworks for real-time, fully client-rendered apps

</integration>


<critical_reminders>

CRITICAL REMINDERS

All code must follow project conventions in CLAUDE.md

(You MUST keep pages static by default - only add export const prerender = false when the page genuinely needs request-time data)

*(You MUST use `client:` directives on framework components that need interactivity - without a directive, components render to static HTML with zero JavaScript)**

(You MUST define content collections in src/content.config.ts with Zod schemas for type-safe frontmatter)

(You MUST use <ClientRouter /> from astro:transitions for View Transitions - the old <ViewTransitions /> component is removed in Astro 6)

(You MUST install a server adapter (@astrojs/node, @astrojs/vercel, etc.) before using on-demand rendering)

(You MUST use getStaticPaths() for dynamic routes in static mode - it is not needed for on-demand (SSR) routes)

Failure to follow these rules will ship unnecessary JavaScript, break builds, cause missing pages, or produce type errors.

</critical_reminders>