astro

Use when creating or modifying .astro/.tsx files, configuring astro.config.mjs, working with Content Collections, or when TypeScript or build errors occur.

SKILL.md

GitHub

Astro Framework Skill

Domain

Astro 6+ patterns, Islands Architecture, Content Collections, routing, build

KPIs

Metric Target Measurement
TypeScript Errors 0 npm run check (astro check — 0 errors)
Build Warnings 0 npm run build 2>&1 | grep -i "warn" | wc -l
Build Time <3s npm run build timing output
Deprecated patterns / relative imports 0 npm run check:kpis

Rules

ClientRouter (NOT ViewTransitions)

---
// ✅ Astro 6
import { ClientRouter } from 'astro:transitions';
---
<head>
  <ClientRouter />
</head>

// ❌ Deprecated
import { ViewTransitions } from 'astro:transitions';

Zod Import

// ✅ Astro 6
import { z } from 'astro/zod';

// ❌ Deprecated
import { z } from 'astro:content';
import { z } from 'astro:schema';

Content Collections

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

const blog = defineCollection({
  loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content/blog' }),
  schema: z.object({
    title: z.string(),
    description: z.string(),
    pubDate: z.coerce.date(),
    draft: z.boolean().optional(),
  }),
});

export const collections = { blog };
---
// Usage in pages
import { getCollection } from 'astro:content';
const posts = await getCollection('blog');
---

.astro vs .tsx Decision

Use .astro when... Use .tsx when...
Static content Client-side interactivity needed
Server-side rendering State management needed
Layout components Event handlers needed
Section components Forms with validation
SEO/meta components Complex UI (dialogs, dropdowns)

Client Directives

<!-- Load immediately (above-the-fold interactivity) -->
<Component client:load />

<!-- Load when visible (below-the-fold) -->
<Component client:visible />

<!-- Load on idle (non-critical UI) -->
<Component client:idle />

<!-- Only on a specific platform -->
<Component client:only="react" />

Rule of thumb: client:visible > client:idle > client:load. Use client:load only for immediately visible interactive elements.

Props Interface Pattern

---
interface Props {
  title: string;
  description?: string;
  variant?: 'default' | 'compact' | 'wide';
  class?: string;
}

const {
  title,
  description,
  variant = 'default',
  class: className,
} = Astro.props;
---

Slot Composition

<!-- Named slots -->
<section>
  <div class="header">
    <slot name="header" />
  </div>
  <div class="content">
    <slot />  <!-- Default slot -->
  </div>
  <div class="footer">
    <slot name="footer" />
  </div>
</section>

astro.config.mjs Patterns

import { defineConfig } from 'astro/config';
import tailwindcss from '@tailwindcss/vite';
import react from '@astrojs/react';
import sitemap from '@astrojs/sitemap';

export default defineConfig({
  site: 'https://example.com',
  integrations: [react(), sitemap()],
  vite: {
    plugins: [tailwindcss()],
  },
});

Import Alias

Always use @/ (configured in tsconfig.json):

// ✅
import Hero from '@/components/sections/Hero.astro';
import { Button } from '@/components/ui/button';

// ❌
import Hero from '../../components/sections/Hero.astro';

Non-Negotiable

These rules always apply — even under time pressure, even when "it works anyway":

  • No ViewTransitions. Always ClientRouter. "But the docs say ViewTransitions" — those docs are outdated; Astro 6 uses ClientRouter.
  • No z from astro:content or astro:schema. Always import { z } from 'astro/zod'. Other imports compile but break Content Collections.
  • No commit with TypeScript errors. "It's just a type error, it still works" — type errors in .astro files become runtime bugs.
  • Always the @/ import alias. Relative imports (../../) work, but every file move breaks them. @/ is refactoring-safe.
  • No client:load without good reason. client:visible or client:idle are almost always better. "I need it immediately" is rarely true for below-the-fold elements.

The convention guard hook (.claude/hooks/guard-conventions.mjs) blocks the deprecated patterns automatically and warns on relative imports.

Before Applying

Read LEARNINGS.md in this directory to avoid known anti-patterns.