Aller au contenu principal

Rules: astro

Astro renders zero JS by default. Components are static HTML unless explicitly "hydrated" via client:* directives. Use Astro for content-heavy sites (blogs, docs, marketing) and not for interact

Affected files

These rules apply to files matching the following patterns:

  • **/*.astro
  • **/astro.config.*
  • **/content/**/*.md
  • **/content/**/*.mdx

Detailed rules

Astro Rules

Philosophy: Islands Architecture

Astro renders zero JS by default. Components are static HTML unless explicitly "hydrated" via client:* directives. Use Astro for content-heavy sites (blogs, docs, marketing) and not for interactive full-SPA dashboards.

.astro components

---
// Frontmatter: TypeScript, runs at build time
import Layout from '../layouts/Layout.astro'
import Card from '../components/Card.astro'

interface Props {
title: string
}
const { title } = Astro.props
const posts = await getPosts() // Fetched at build, not at runtime
---

<Layout>
<h1>{title}</h1>
{posts.map(post => <Card {...post} />)}
</Layout>

<style>
h1 { color: var(--accent); } /* Automatically scoped */
</style>

Client directives (hydration)

DirectiveUsage
client:loadImmediate hydration (avoid except for critical cases)
client:idleHydration when the browser is idle
client:visibleHydration when the component enters the viewport (recommended default)
client:media="(max-width: 768px)"Hydration based on media query
client:only="react"100% client rendering (no SSR, loading fallback)
---
import Counter from '../components/Counter.tsx'
---

<!-- Static HTML -->
<Counter client:visible />

Rule: client:visible by default. client:load only if above-the-fold and immediate interactivity is required.

Framework integrations

Astro supports React, Vue, Svelte, Solid, Preact at the same time:

// astro.config.mjs
import { defineConfig } from 'astro/config'
import react from '@astrojs/react'
import svelte from '@astrojs/svelte'

export default defineConfig({
integrations: [react(), svelte()],
})

Use framework components for interactive islands only. For static content, prefer .astro components (lighter).

Content Collections

// src/content/config.ts
import { defineCollection, z } from 'astro:content'

const blog = defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
date: z.date(),
draft: z.boolean().default(false),
tags: z.array(z.string()),
}),
})

export const collections = { blog }
---
import { getCollection } from 'astro:content'

const posts = await getCollection('blog', ({ data }) => !data.draft)
---

Type-safe, Zod validation at build time, files in src/content/blog/*.md.

Rendering modes

ModeConfigUsage
StaticdefaultBlogs, docs, marketing (prerendered)
Hybridoutput: 'hybrid'Static by default, export const prerender = false per page to opt out
Serveroutput: 'server'SSR by default, export const prerender = true per page to opt in

Choose hybrid for most cases: the best of both worlds.

View Transitions (Astro 3+)

---
import { ViewTransitions } from 'astro:transitions'
---

<html>
<head>
<ViewTransitions />
</head>
</html>

Enables transition animations between pages, SPA feel without a framework.

Anti-patterns

AvoidPrefer
React component everywhere.astro for static, framework for islands
client:load by defaultclient:visible
Fetch inside the .astro component at runtimegetStaticPaths() or Content Collections at build time
document.querySelector inside <script> without event listenerProperly scoped scripts with is:inline if needed
Astro for full-SPA dashboardNext.js / SvelteKit are better suited

Performance

  • Zero JS by default → typical Lighthouse 100
  • Native image optimization: <Image src={img} alt="" /> from astro:assets
  • CSS scoped to the component (no collisions)
  • Automatic prefetching of internal links (opt-in config)

Rules

IMPORTANT: Astro = content sites (blog, docs, marketing), NOT SPA dashboards. IMPORTANT: client:visible by default for islands (not client:load). YOU MUST use Content Collections for structured content (type-safe Zod validation). YOU MUST prefer .astro components over framework components when there is no interactivity. NEVER use client:load everywhere — it cancels Astro's zero-JS benefit.

Automatic application

These rules are automatically applied by Claude during:

  • Reading the matching files
  • Modifying code
  • Suggestions and fixes

See also