Skip to content
cccskills
FreePublished on GitHub

web-meta-framework-astro

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

The English summary is being prepared. Showing the original description.

See how to install

Files included (8)

  • SKILL.md14.9 KB
  • examples/content.md10.0 KB
  • examples/core.md6.6 KB
  • examples/integrations.md7.6 KB
  • examples/islands.md8.0 KB
  • examples/routing.md7.7 KB
  • metadata.yaml388 B
  • reference.md3.0 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

Astro Patterns

Quick Guide: Astro renders pages to static HTML with zero client JavaScript by default. .astro components carry static content; framework components become interactive islands only when given a client:* directive. Content collections give structured Markdown type-safe frontmatter through Zod schemas. Rendering mode is per page: static unless export const prerender = false. Astro 6 replaced <ViewTransitions /> with <ClientRouter />, replaced Astro.glob() with import.meta.glob(), moved z from astro:content to astro/zod (now Zod 4), requires string getStaticPaths() params, and requires Node 22.12.0+.

Detailed Resources:

  • examples/core.md — typed props, expressions, nested layouts, scoped vs global styles, script handling
  • examples/islands.md — directive selection, client:only, multi-framework islands, server islands, cross-island state
  • examples/content.md — collection schemas, querying, rendering, references, custom loaders, live collections
  • examples/routing.md — static and dynamic routes, rest params, pagination, on-demand routes, endpoints, 404
  • examples/integrations.md — framework integrations, View Transitions, persistence, animations, Starlight
  • reference.md — project layout, route priority, collection API, adapters, rendering checklist

Which path applies

  • Every page is static — the default. No output setting and no adapter; dynamic routes need getStaticPaths(). Follow examples/routing.md.
  • A few pages need request-time data — keep the default, add export const prerender = false to those pages, and install a server adapter. Same file, plus the adapter table in reference.md.
  • Most pages need request-time data — set output: "server" and opt individual pages back to static with export const prerender = true.

<critical_requirements>

Before writing Astro code

Leave pages static and add export const prerender = false only where the page reads request-time data. Static is the default and is where the framework's speed comes from.

Install a server adapter before any page opts out of prerendering. Without one, a build containing prerender = false fails.

Give a framework component a client:* directive when it needs to be interactive. Without a directive it renders to static HTML and its event handlers never run.

Define collections in src/content.config.ts with a Zod schema. The schema validates frontmatter at build time and generates the types the queries return.

Use getStaticPaths() for dynamic routes in static mode. On-demand routes read Astro.params directly and need no such export.

</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

Applies to:

  • .astro component syntax — frontmatter, template expressions, slots, layouts, scoped styles
  • Islands: client directives, hydration timing, server islands, mixing UI frameworks on one page
  • Content collections: schemas, loaders, querying, rendering, cross-collection references
  • File-based routing: static, dynamic, rest parameters, pagination, API endpoints
  • Rendering mode: static, on-demand, and per-page prerender control
  • View Transitions: <ClientRouter />, transition directives, persisted elements

Handled elsewhere:

  • What an island renders internally — a hydrated component follows the conventions of whichever UI library wrote it, and Astro settles only the boundary.
  • Which CSS approach fills a <style> block — the scoping rules here are Astro's; the styling system is not.
  • Which store library fills the cross-island seam — that islands share no tree, and that a module-scoped store is the way across, is settled in examples/islands.md; which store you reach for is not.
  • Fully interactive applications where every route is user-specific — that shape wants a framework whose default is on-demand rendering rather than one whose default is static output.

<philosophy>

Astro is a content-first framework that ships zero JavaScript by default. Most of a page is static HTML; small interactive "islands" hydrate independently, each paying only for itself.

Four consequences follow, and they explain most of the API:

  1. A component is static until told otherwise — client:* is the opt-in, so the cost of interactivity is always visible at the call site.
  2. The UI library is a detail — React, Vue, Svelte, Solid and Preact components are all just island contents, and one page can carry several.
  3. Content is typed data — collections put a Zod schema between Markdown frontmatter and the code that reads it, so a typo in a post fails the build rather than the page.
  4. Rendering mode is per page — static and on-demand pages coexist in one project, which is why prerender is an export rather than a global setting.
</philosophy>

<decision_framework>

Static or on-demand? A page needs on-demand rendering when it reads cookies, headers or user-specific data at request time, or when its data changes faster than you are willing to rebuild. Everything else is static — including data that changes hourly, which a rebuild handles more cheaply than an adapter does.

.astro or a framework component? No client-side interactivity means .astro — zero JavaScript. Simple interactivity (a toggle, a show/hide) is .astro plus a <script> tag, which is lighter than a framework. Reach for a framework component when the interaction needs that framework's own state model.

Which client directive? The table in Pattern 4 maps each one to what it is for. client:only is the last resort, for a component that cannot server-render at all.

Build-time or live collection? defineCollection for anything that is the same on every request — posts, docs, changelogs, author bios. defineLiveCollection only when the data must be fresh per request (inventory, pricing), which also forces that page into on-demand rendering.

</decision_framework>


<patterns>

Core patterns

Pattern 1: Astro component structure

An .astro file is a server-only script between --- fences followed by an HTML template. The script never reaches the browser, so data fetching belongs there.

---
interface Props { title: string; description?: string }
const { title, description = "Default" } = Astro.props;
const posts = await getCollection("blog");
---

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

<style>h1 { color: navy; }</style>

Styles in a <style> block are scoped to the component unless marked is:global.

Full code: examples/core.md

Pattern 2: Slots for composition

A <slot /> receives content from the parent. Named slots take a matching slot="name" attribute, and anything inside the <slot> element is fallback content when nothing is passed.

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

Full code: examples/core.md

Pattern 3: Layouts

A layout is an ordinary component that wraps page content through its default slot, and layouts nest — a blog layout wrapping a base layout wrapping the page.

---
const { title } = Astro.props;
---
<html lang="en">
  <head><title>{title}</title></head>
  <body><main><slot /></main></body>
</html>

Full code: examples/core.md

Pattern 4: Islands and client directives

Framework components render to static HTML until a client:* directive hydrates them. The directive chooses when hydration happens.

DirectiveHydratesUse for
client:loadImmediately on page loadCritical interactive UI
client:idleWhen the browser is idleLower-priority interactivity
client:visibleWhen it scrolls into the viewportBelow-the-fold content
client:mediaWhen a media query matchesResponsive interactivity
client:onlyClient only, skipping the server renderBrowser-dependent components
<Header />                                   <!-- static, zero JS -->
<SearchBar client:load />
<Comments client:visible />
<Analytics client:media="(max-width: 768px)" />

Full code: examples/islands.md

Pattern 5: Server islands

server:defer renders a component per request while the rest of the page stays cacheable. The fallback slot holds its place until it arrives.

<ProductInfo product={product} />

<UserReviews server:defer>
  <div slot="fallback">Loading reviews...</div>
</UserReviews>

Full code: examples/islands.md

Pattern 6: Content collections

A collection pairs a loader with a Zod schema. getCollection queries it with an optional filter, and render() turns an entry's Markdown into a component.

// src/content.config.ts
const blog = defineCollection({
  loader: glob({ pattern: "**/*.md", base: "./src/content/blog" }),
  schema: z.object({
    title: z.string(),
    pubDate: z.coerce.date(),
    draft: z.boolean().default(false),
  }),
});
export const collections = { blog };
const posts = await getCollection("blog", ({ data }) => !data.draft);
const { Content, headings } = await render(post);

Live collections are a separate mechanism: defineLiveCollection in src/live.config.ts (not content.config.ts), queried with getLiveCollection() / getLiveEntry(), and only from on-demand pages.

Full code: examples/content.md

Pattern 7: File-based routing

src/pages/ maps to URLs. [param] is a single dynamic segment, [...rest] matches any depth, and a leading underscore excludes a file from routing.

src/pages/
├── index.astro          → /
├── blog/[id].astro      → /blog/:id
├── docs/[...slug].astro → /docs and /docs/*
└── _helpers.ts          → not a route

In static mode each dynamic route exports getStaticPaths() returning { params, props } pairs; paginate() inside it generates numbered pages.

Full code: examples/routing.md

Pattern 8: On-demand rendering and endpoints

export const prerender = false moves a page to request time, where Astro.cookies, Astro.redirect() and a Response return value all become available. API endpoints are .ts files exporting one handler per HTTP method, and they default to static like everything else.

export const prerender = false;

export const GET: APIRoute = async ({ url }) => {
  const query = url.searchParams.get("q");
  if (!query)
    return new Response(JSON.stringify({ error: "Missing query" }), {
      status: 400,
    });
  return new Response(JSON.stringify(await searchDatabase(query)));
};

Full code: examples/routing.md

Pattern 9: View Transitions

<ClientRouter /> in the document head enables cross-page transitions. transition:name pairs elements so they morph, and transition:persist keeps an element alive across a navigation.

<head><ClientRouter /></head>

<img src={post.data.heroImage} transition:name={`hero-${post.id}`} transition:animate="slide" />
<audio controls transition:persist><source src="/music.mp3" type="audio/mp3" /></audio>

Full code: examples/integrations.md

</patterns>

<red_flags>

Red flags

Breaks at runtime:

  • A dynamic route in static mode with no getStaticPaths() — the build fails with "getStaticPaths() is required".
  • prerender = false with no server adapter installed — the build fails.
  • <ViewTransitions /> — removed in Astro 6; import <ClientRouter /> from astro:transitions.
  • Astro.glob() — removed in Astro 6; use import.meta.glob().
  • import { z } from "astro:content" — removed in Astro 6; import z from astro/zod, which is Zod 4, so z.string().email() is now z.email().
  • Numeric getStaticPaths() params — Astro 6 requires strings; wrap with String(id).
  • astro.config.cjs — Astro 6 requires ESM (.mjs or .ts).
  • Functions, class instances or symbols passed as props to a hydrated component — island props must be serializable.
  • Astro.props read outside the frontmatter fence, or an .astro component imported into a framework component — neither is available there.
  • Astro 6 on Node below 22.12.0 — unsupported.

Surprising behaviour:

  • client:load on everything defeats the architecture; a component with no interactivity wants no directive at all.
  • client:only skips the server render, so nothing is in the HTML for crawlers — prefer client:load wherever the component can render on the server.
  • Data fetched in a <script> tag creates a client waterfall; frontmatter runs server-side and has no such cost.
  • A collection with no schema loses both build-time validation and generated types.
  • output: "server" on a mostly-static site gives up the default's caching for pages that did not need it.
  • Unfiltered getCollection returns drafts alongside published entries.
  • <style> is scoped by default — reach for <style is:global> or the :global() selector deliberately.
  • <script> is bundled and deduped; is:inline opts out, which is what makes a script re-run on every View Transitions navigation.
  • client:visible waits on IntersectionObserver, so a component that is never on screen never hydrates.
  • Astro.redirect() works only on on-demand pages; a static page cannot redirect at request time.
  • Islands share no state — cross-island communication needs a store or events you bring.
  • transition:persist needs the same transition:name on both pages, or the element is recreated.
  • Collection entry ids come from filenames unless frontmatter overrides them.
  • Live collections cannot render MDX, and import.meta.env is inlined at build time — read runtime secrets from process.env.
  • A [...slug] route matches its own base path when a params entry passes undefined.

</red_flags>

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

Hugging Face Inference SDK patterns for TypeScript/Node.js — InferenceClient setup, chat completion, text generation, streaming, embeddings, image generation, audio transcription, translation, summarization, and Inference Endpoints

The English summary is being prepared. Showing the original description.

agents-inc/skills25Updated Oct 17, 2026

LiteLLM proxy server setup, TypeScript client patterns via OpenAI SDK, model routing, fallbacks, load balancing, spend tracking, virtual keys, and production deployment

The English summary is being prepared. Showing the original description.

agents-inc/skills25Updated Oct 17, 2026

Serverless GPU compute platform for AI model deployment — web endpoints, GPU functions, model serving, and TypeScript client patterns

The English summary is being prepared. Showing the original description.

agents-inc/skills25Updated Oct 17, 2026

Local LLM inference with the Ollama JavaScript client -- chat, streaming, tool calling, vision, embeddings, structured output, model management, and OpenAI-compatible endpoint

The English summary is being prepared. Showing the original description.

agents-inc/skills25Updated Oct 17, 2026

Replicate SDK patterns for TypeScript/Node.js -- client setup, predictions, streaming, webhooks, file handling, model versioning, deployments, and training

The English summary is being prepared. Showing the original description.

agents-inc/skills25Updated Oct 17, 2026

Together AI SDK patterns for TypeScript — client setup, chat completions, streaming, structured output, function calling, embeddings, image generation, fine-tuning, and OpenAI-compatible endpoints

The English summary is being prepared. Showing the original description.

agents-inc/skills25Updated Oct 17, 2026

See all skills by agents-inc

Report a problem with this skill