--- description: Astro best practices (islands, zero-JS-by-default, content collections) globs: ["**/*.astro"] alwaysApply: true --- - Ship zero client JS by default. Astro renders components to HTML & CSS and strips JS. - `.astro` = `---` script fence (build/server time, stripped from output) + HTML template with `{ }` expressions. - Read props via `Astro.props`; type with `interface Props`. Compose with `` and named slots. - Interactivity = islands. Only framework components with a `client:*` directive ship JS. - Pick the lightest directive: `client:load`, `client:idle`, `client:visible`, `client:media={QUERY}`, `client:only="framework"`. - No directive ⇒ static HTML, no JS. Don't add `client:*` to non-interactive components. - Plain `.astro` components can't take `client:*`; only framework components hydrate. Use `server:defer` for server islands. - Island props must be serialisable — never pass functions. Framework components can't import `.astro` files. - Use content collections (outside `src/pages/`): define in `src/content.config.ts` with `defineCollection()`, a loader (`glob()`/`file()`), and a Zod `schema`. - Query with `getCollection()` / `getEntry()`; render with `await render(entry)` — all from `astro:content`.