☰ Categories

Astro.js

# Astro v6 Architecture Rules (Strict Mode) ## 1.

CategoryDevelopment › Coding
TagsDraftingReviewingDeveloperCode
Prompt
# Astro v6 Architecture Rules (Strict Mode)

## 1. Core Philosophy

- Follow Astro’s “HTML-first / zero JavaScript by default” principle:
  - Everything is static HTML unless interactivity is explicitly required.
  - JavaScript is a cost → only add when it creates real user value.

- Always think in “Islands Architecture”:
  - The page is static HTML
  - Interactive parts are isolated islands
  - Never treat the whole page as an app

- Before writing any JavaScript, always ask:
  "Can this be solved with HTML + CSS or server-side logic?"

---

## 2. Component Model

- Use `.astro` components for:
  - Layout
  - Composition
  - Static UI
  - Data fetching
  - Server-side logic (frontmatter)

- `.astro` components:
  - Run at build-time or server-side
  - Do NOT ship JavaScript by default
  - Must remain framework-agnostic

- NEVER use React/Vue/Svelte hooks inside `.astro`

---

## 3. Islands (Interactive Components)

- Only use framework components (React, Vue, Svelte, etc.) for interactivity.

- Treat every interactive component as an isolated island:
  - Independent
  - Self-contained
  - Minimal scope

- NEVER:
  - Hydrate entire pages or layouts
  - Wrap large trees in a single island
  - Create many small islands in loops unnecessarily

- Prefer:
  - Static list rendering
  - Hydrate only the minimal interactive unit

---

## 4. Hydration Strategy (Critical)

- Always explicitly define hydration using `client:*` directives.

- Choose the LOWEST possible priority:

  - `client:load`
    → Only for critical, above-the-fold interactivity

  - `client:idle`
    → For secondary UI after page load

  - `client:visible`
    → For below-the-fold or heavy components

  - `client:media`
    → For responsive / conditional UI

  - `client:only`
    → ONLY when SSR breaks (window, localStorage, etc.)

- Default rule:
  ❌ Never default to `client:load`
  ✅ Prefer `client:visible` or `client:idle`

- Hydration is a performance budget:
  - Every island adds JS
  - Keep total JS minimal

📌 Astro does NOT hydrate components unless explicitly told via `client:*` :contentReference[oaicite:0]{index=0}  

---

## 5. Server vs Client Logic

- Prefer server-side logic (inside `.astro` frontmatter) for:
  - Data fetching
  - Transformations
  - Filtering / sorting
  - Derived values

- Only use client-side state when:
  - User interaction requires it
  - Real-time updates are needed

- Avoid:
  - Duplicating logic on client
  - Moving server logic into islands

---

## 6. State Management

- Avoid client state unless strictly necessary.

- If needed:
  - Scope state inside the island only
  - Do NOT create global app state unless required

- For cross-island state:
  - Use lightweight shared stores (e.g., nano stores)
  - Avoid heavy global state systems by default

---

## 7. Performance Constraints (Hard Rules)

- Minimize JavaScript shipped to client:
  - Astro only loads JS for hydrated components :contentReference[oaicite:1]{index=1}  

- Prefer:
  - Static rendering
  - Partial hydration
  - Lazy hydration

- Avoid:
  - Hydrating large lists
  - Repeated islands in loops
  - Overusing `client:load`

- Each island:
  - Has its own bundle
  - Loads independently
  - Should remain small and focused :contentReference[oaicite:2]{index=2}  

---

## 8. File & Project Structure

- `/pages`
  - Entry points (SSG/SSR)
  - No client logic

- `/components`
  - Shared UI
  - Islands live here

- `/layouts`
  - Static wrappers only

- `/content`
  - Markdown / CMS data

- Keep `.astro` files focused on composition, not behavior

---

## 9. Anti-Patterns (Strictly Forbidden)

- ❌ Using hooks in `.astro`
- ❌ Turning Astro into SPA architecture
- ❌ Hydrating entire layout/page
- ❌ Using `client:load` everywhere
- ❌ Mapping lists into hydrated components
- ❌ Using client JS for static problems
- ❌ Replacing server logic with client logic

---

## 10. Preferred Patterns

- ✅ Static-first rendering
- ✅ Minimal, isolated islands
- ✅ Lazy hydration (`visible`, `idle`)
- ✅ Server-side computation
- ✅ HTML + CSS before JS
- ✅ Progressive enhancement

---

## 11. Decision Framework (VERY IMPORTANT)

For every feature:

1. Can this be static HTML?
   → YES → Use `.astro`

2. Does it require interaction?
   → NO → Stay static

3. Does it require JS?
   → YES → Create an island

4. When should it load?
   → Choose LOWEST priority `client:*`

---

## 12. Mental Model (Non-Negotiable)

- Astro is NOT:
  - Next.js
  - SPA framework
  - React-first system

- Astro IS:
  - Static-first renderer
  - Partial hydration system
  - Performance-first architecture

- Think:
  ❌ “Build an app”
  ✅ “Ship HTML + sprinkle JS”

What this prompt does

This prompt enforces Astro v6 architecture rules around static HTML and minimal JavaScript. It emphasizes client:* hydration choices and island structure, though only the earlier rules are visible in the truncated body.

Model comparison

ChatGPT is the most accurate and appropriately concise. Claude overbuilds the solution, while Gemini retains repeated islands.

ChatGPTTop overall
46/ 50

+ Gives the key decisions and fix concisely.

- Claiming one separate bundle per product is imprecise.

Claude
40/ 50

+ Clearly details static cards and minimal islands.

- The assumed cart design is excessive and incomplete.

Gemini
40/ 50

+ Systematically compares issues and alternatives.

- Per-button islands do not adequately reduce repetition.

CriterionChatGPTClaudeGeminiLeader
Instruction following1098ChatGPT +11%
Accuracy977ChatGPT +29%
Specificity899Tie
Structure999Tie
Right length1067ChatGPT +43%

Scored 1–10 by gpt-5.6-sol with model names hidden (2026-09-24). This is an AI review, not a measurement.

Read full answers

We gave three models the same input and copied their answers unedited. Each ran in its CLI (an agent harness), and answers in the ChatGPT or Claude apps or on the web may differ. Outputs are in Korean.

Input used
[Pasted material]
이 규칙에 맞춰서 아래 상품 목록 페이지 컴포넌트를 리뷰하고 고쳐줘. 전부 client:load를 걸어놔서 그런지 초기 로딩이 느리다는 피드백을 받았어.

```astro
---
import ProductCard from '../components/ProductCard.jsx';
import Header from '../components/Header.jsx';
import Footer from '../components/Footer.jsx';
import { getProducts } from '../lib/api';

const products = await getProducts();
---
<html>
  <body>
    <Header client:load />
    <main>
      {products.map((p) => (
        <ProductCard client:load product={p} />
      ))}
    </main>
    <Footer client:load />
  </body>
</html>
```

상품 카드처럼 반복되는 걸 이렇게 하이드레이트해도 되는지, Header/Footer는 굳이 client:load가 필요한지 판단해서 고쳐줘.
gpt-5.6-luna (codex CLI · 에이전트 하네스) · Run on 2026-09-24

반복되는 ProductCard마다 client:load를 붙이는 것은 피해야 합니다. 상품 수만큼 JS 번들과 하이드레이션 작업이 발생해 초기 로딩이 느려집니다.

Header와 Footer도 정적 UI라면 client:load가 필요 없습니다. .astro 컴포넌트로 변경하고, 상호작용이 필요한 부분만 별도 island로 분리하는 것이 좋습니다.

---
import ProductCard from '../components/ProductCard.astro';
import Header from '../components/Header.astro';
import Footer from '../components/Footer.astro';
import { getProducts } from '../lib/api';

const products = await getProducts();
---

<html lang="ko">
  <body>
    <Header />

    <main>
      {products.map((product) => (
        <ProductCard product={product} />
      ))}
    </main>

    <Footer />
  </body>
</html>

판단은 다음과 같습니다.

  • ProductCard: 상품명, 이미지, 가격, 링크처럼 정적인 내용이면 .astro로 작성하고 하이드레이트하지 않습니다.
  • Header: 로고와 내비게이션만 있으면 .astro로 작성합니다. 모바일 메뉴가 필요하다면 Header 전체가 아니라 메뉴 토글만 별도 컴포넌트로 분리합니다.
<!-- Header.astro -->
---
import MobileMenuButton from './MobileMenuButton.jsx';
---

<header>
  <a href="/">브랜드</a>
  <nav>...</nav>

  <MobileMenuButton client:idle />
</header>
  • Footer: 정적 링크와 정보만 있으면 하이드레이션하지 않습니다.
  • 상품 카드의 장바구니 버튼처럼 상호작용이 필요해도 카드 전체를 island로 만들지 말고, 버튼만 분리합니다. 다만 카드마다 island를 반복하면 비용이 커질 수 있으므로 가능하면 HTML <form>과 서버 처리 또는 링크 기반으로 구현하는 편이 좋습니다.

client:visible로 바꾸는 것만으로는 반복 island 문제가 해결되지 않습니다. 각 카드가 정말 클라이언트 상태를 필요로 할 때만 제한적으로 사용하세요.

More in this category

12-Month AI and Computer Vision Roadmap for Defense Applications
2046 Puzzle Game Challenge
21st.dev component prompt
3D FACTORY
3D FPS Game