К основному содержанию
скилл CX Codex

nextjs-app-architecture — скилл для Claude Code: архитектура Next.js

Скилл задаёт единую архитектуру App Router в Next.js 16: страницы только компонуют, данные читают фичи. Пригодится при старте проекта и при разборе чужого кода.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add aurorascharff/nextjs-app-architecture-skill --skill nextjs-app-architecture -a claude-code
Открыть на GitHub

Что делает nextjs-app-architecture

Скилл ведёт агента по шагам: сначала выбрать режим — собрать приложение с нуля или провести аудит существующего, потом разложить работу по фичам, написать запросы и экшены, собрать компонент со скелетоном. Каждый шаг ссылается на справочник в references/ — по фичам, запросам и экшенам, кэш-компонентам, одностраничным приложениям. Механику фреймворка скилл не пересказывает, а отправляет за ней в документацию Next.js.

Внутри 11 инвариантов, которым должно соответствовать любое изменение. Страницы и лейауты остаются синхронными через params.then(), фичи получают id или slug вместо сырых params, запросы лежат в <domain>-queries.ts с import 'server-only', экшены — в <domain>-actions.ts с 'use server'. Границу <Suspense> ставит страница, а скелетон живёт в том же файле, что и компонент.

Перед первым запуском нужно подготовить проект: скилл требует, чтобы у агента был доступ к документации под свою версию Next.js — через AGENTS.md или встроенные доки, и советует создать их, если их нет. Без этого шага агент будет опираться на память, а версии API в Next.js 16 расходятся с прежними. Часть ссылок ведёт на preview.nextjs.org, то есть на canary-API.

Какие задачи решает

  • разложить страницы App Router по фичам, а не по маршрутам
  • переписать страницу-загрузчик в асинхронный серверный компонент
  • решить, где живут запросы, экшены и компоненты
  • расставить границы Suspense и не потерять статичный каркас
  • вынести скелетоны так, чтобы не прыгала вёрстка при загрузке

Примеры запросов агенту

  • проведи аудит app/ и покажи, где страницы сами делают запросы
  • добавь фичу избранного по этой архитектуре
  • включи Cache Components и расставь теги кэша для ленты

Как установить nextjs-app-architecture

1Через Skills CLI (Vercel)

npx skills add aurorascharff/nextjs-app-architecture-skill --skill nextjs-app-architecture -a claude-code

2Вручную: положить файлы

~/.claude/skills/nextjs-app-architecture/SKILL.md

Папка скилла целиком; для одного проекта — .claude/skills/nextjs-app-architecture/

По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов

Вопросы о nextjs-app-architecture

Как установить nextjs-app-architecture в Claude?

Выполните npx skills add aurorascharff/nextjs-app-architecture-skill --skill nextjs-app-architecture -a claude-code. Скилл встанет в ~/.claude/skills/nextjs-app-architecture/SKILL.md.

Что делает nextjs-app-architecture?

Задаёт порядок работы над приложением на Next.js 16 App Router: где размещать фичи, как писать запросы и экшены, как ставить Suspense и скелетоны. Работает и при сборке с нуля, и при разборе существующего кода.

Что нужно подготовить до запуска скилла?

Проект должен быть настроен так, чтобы агент читал документацию под свою версию Next.js — через AGENTS.md или встроенные доки. Скилл советует создать или обновить их, если их нет.

Исходный текст

SKILL.md · MIT
---
name: nextjs-app-architecture
description: Build or audit Next.js 16 App Router apps using a next-beats-style React Server Components architecture. Use when scaffolding a new app, adding a feature, reviewing an existing app, refactoring route-loader-shaped pages into feature-owned async server components, deciding where queries/actions/components live, keeping pages synchronous with `params.then()`, placing Suspense boundaries, choosing the client/server boundary, designing skeletons, preventing CLS, or enabling Cache Components. Also use when the user asks about RSC composition, components receiving IDs instead of route params, `'use cache'`, `cacheTag`, `updateTag`, static-shell prerendering, or making an app easier for AI agents to modify.
license: MIT
metadata:
  author: aurorascharff
  version: "1.4.1"
---

# Next.js App Architecture

A workflow for building and auditing Next.js 16+ App Router apps so they follow one consistent, feature-sliced RSC architecture like `next-beats`.

**Follow the workflow below step by step** — it produces the invariants by construction. Load the reference a step names for the decision it depends on. Get framework _mechanics_ (API signatures, config options, hook contracts) from the linked docs — don't restate or improvise them. Links for canary-only Next.js APIs use `preview.nextjs.org`.

## Prerequisite

Before changing a Next.js app, make sure the project is set up for AI agents to read version-matched docs. Follow the [AI Coding Agents guide](https://preview.nextjs.org/docs/app/guides/ai-agents): prefer the project's `AGENTS.md` / bundled docs, and create or refresh them when missing. Then use this skill for architecture decisions.

## Architecture target

Build pages that describe the loading experience, not pages that act like route loaders:

- `app/**/page.tsx` and `layout.tsx` are synchronous composition surfaces: static chrome, section headings, `<Suspense>` boundaries, error boundaries, and transition wrappers.
- Feature components own their reads on the server. They receive minimal stable inputs (`id`, `slug`, `handle`, parsed filter values) or already-fetched records, never raw `params` / `searchParams`.
- Queries and actions live in the feature folder. Components import queries; client leaves import actions directly.
- When server tags and client query keys describe the same feature data, a pure feature-local cache contract owns those identities.
- Stable chrome, wrappers, and skeletons preserve layout: cards/panels stay outside Suspense, and fallbacks swap only the data-dependent body.

## Invariants (what every change must satisfy)

The non-negotiables. The workflow produces them; the final check verifies them.

1. **Pages compose, they never fetch.** A page/layout imports feature components and places `<Suspense>`. No queries or domain logic inline. Tiny route-local control-flow helpers are allowed only when they exist to place a boundary around `connection()`, `redirect()`, or a resolved route prop.
2. **Pages stay synchronous.** Use `params.then()` / `searchParams.then()` or `Promise.all([params, searchParams]).then(...)`, never `await params` at the top — so chrome paints into the static shell and only data-dependent sections suspend.
3. **Feature components receive IDs, not route props.** Resolve `params` / `searchParams` at the page boundary and pass plain values (`id`, `slug`, `query`) into features.
4. **Async server component is the default.** `'use client'` only for hooks, event handlers, or browser APIs — and only on leaves, never on parents of server content.
5. **The page owns the Suspense boundary; the feature owns the skeleton.** Features never pre-wrap themselves in `<Suspense>`; stable wrappers/cards/chrome wrap the boundary instead of being duplicated in fallback and final content.
6. **Skeletons live in the same file as the component**, exported alongside it, defined at the end. `Feed` and `FeedSkeleton` are siblings.
7. **Queries live in `<domain>-queries.ts`** (`import 'server-only'`); **actions live in `<domain>-actions.ts`** (`'use server'`). The file name matches the folder, even for sub-concepts.
8. **Feature folders follow product ownership.** Entity-owned sub-concepts (favorite, like, vote, bookmark) fold into their parent. A route-level experience that composes multiple domains may own its UI and state in a separate feature while each domain keeps its queries and actions.
9. **Client components import actions directly** — never receive a server action as a prop just to call it.
10. **Feature-local cache coordination stays with its domain.** Put pure tags/keys in `<domain>-cache.ts`, client query definitions in `<domain>-query-options.ts`, hook wrappers in `hooks/use-*.ts`, and tiny client leaves in `components/`; promote support code only after real cross-feature reuse.
11. **Interactive async UI keeps server data on the server and client state local to the interaction.** Use `useOptimistic`, `useTransition`, reducers, URL/search params, and form actions instead of mirrored prop state, derived-state effects, or hand-rolled pending arrays.

## Workflow

Run these in order for build-from-scratch, feature work, or audits. Each step names the reference to consult and the check it must pass.

1. **Choose mode.**
   - **Build from scratch:** sketch routes, real domain nouns, static shell, and expected loading groups before writing code.
   - **Audit/refactor:** scan current `app/` pages first; list every async page, page-level query import, route prop leak, missing Suspense boundary, and feature folder mismatch.
     → `references/example.md` for the target shape; `references/feature-folders.md` for placement.
     ✓ You know whether you are creating the architecture or converting loader-shaped code into it.
2. **Place the work.** Decide the feature folder before writing anything.
   → `references/feature-folders.md` (decision tree + merge rules).
   ✓ A real domain, a cross-domain product experience, or folded into the right parent.
3. **Write the query and, when a client cache shares its data, the cache contract.** Put server reads in `<domain>-queries.ts` with `import 'server-only'`; keep shared tag/key identities in a pure `<domain>-cache.ts`.
   → `references/queries-actions.md`; for SWR/TanStack Query → `references/single-page-applications.md`; with `cacheComponents: true`, also → `references/cache-components.md`.
   ✓ Cache identities are defined once; server reads are server-only, cached/tagged/lifetimed under Cache Components, and return domain types rather than ORM rows.
4. **Write the action** (if there's a mutation). `features/<domain>/<domain>-actions.ts`, `'use server'` at the top.
   → `references/queries-actions.md`.
   ✓ Re-checks auth, validates input, invalidates matching cache tags under Cache Components (`refresh()` only for justified dynamic reads), returns a discriminated union.
5. **Build the component + skeleton.** `features/<domain>/components/<name>.tsx`: an async server component that awaits its own query from minimal props; `'use client'` only on interactive leaves.
   → `references/components.md`; for a client data library or strict-SPA/CSR feature → `references/single-page-applications.md`.
   ✓ Component receives IDs/handles/parsed filters or already-resolved records, not `params`; skeleton is a sibling export at the end; no alias skeleton wrappers.
6. **Compose the page.** `app/<route>/page.tsx`: synchronous, `params.then()` / `Promise.all(...).then(...)`, place Suspense around data bodies, and wrap the section that can fail independently in an error boundary.
   → `references/pages-suspense.md`; with `cacheComponents: true`, also → `references/instant-navigation.md` for which links prefetch and which reads wait for the navigation.
   ✓ Route props become plain values; stable cards/sections wrap Suspense when they set layout; boundaries stay visible at the page.
7. **Add interaction** (if any): optimistic updates, pending state, toasts, confirmation.
   → `references/ux-patterns.md`.
   ✓ Feedback isn't doubled; optimistic reducers/actions live with the feature; URL/search params own shareable state; client effects synchronize external systems, not derived React state.
8. **Verify** against the checklist below before declaring done. When the change touches a loading sequence, lock it in with an end-to-end test.
   → `references/testing.md`.
   ✓ The test asserts which content is available before uncached work resolves, using visibility-aware locators.

## Verify before done

Inspect the diff against every invariant — each is checkable by reading the changed files:

- [ ] No page/layout imports a `*-queries` file or defines reusable domain UI inline; any inline helper is route-local control flow only.
- [ ] Every page with params is synchronous and uses `params.then()` / `searchParams.then()` / `Promise.all([params, searchParams]).then(...)`.
- [ ] Feature components receive plain IDs/handles/parsed filters or resolved records; no feature prop is named `params` or `searchParams`.
- [ ] Every `<Suspense>` for page data sits in the page; no feature pre-wraps itself.
- [ ] Stable wrappers/cards/chrome sit outside Suspense; fallback and final content do not duplicate the same outer card.
- [ ] Every component has its real `*Skeleton` in the same file, at the end; no tiny skeleton aliases just to pass props.
- [ ] Skeleton and content are the same height (measured), section headings sit outside the boundary, and sections that can be empty reserve their space.
- [ ] Sections below a variable-height section are nested sibling boundaries inside it, not awaited by it and not passed through it as children.
- [ ] `unstable_prefetch()` / `unstable_navigation()` are awaited in the component before its query call; no wrapper query exists just to hold the gate.
- [ ] Every `*-queries.ts` starts with `import 'server-only'`; every `*-actions.ts` with `'use server'`.
- [ ] With `cacheComponents: true`, reusable reads use `'use cache'` / `cacheTag` / `cacheLife`, or `'use cache: private'` / `'use cache: remote'` when appropriate; any dynamic read is intentional and justified.
- [ ] A personalized shared-cache scope receives trusted, normalized identity values from an uncached feature wrapper; it never reads request APIs or trusts a client-provided identity inside the cache scope.
- [ ] Reads whose every write calls `updateTag()` use `cacheLife('max')`; a shorter profile is reserved for data that changes outside the app's actions.
- [ ] Mutations touching cached reads call `updateTag()` / `revalidateTag(..., 'max')` for the matching tags; `refresh()` is not a substitute for tag invalidation.
- [ ] `prefetch={true}` is reserved for links users predictably follow, or for rows whose per-link prefetch was made cheap by gating the heavy part behind `unstable_navigation()`.
- [ ] Action files are named `<folder>-actions.ts`; no entity-owned sub-concept spawned its own folder, and cross-domain product features do not take ownership of entity queries/actions.
- [ ] Features with both server tags and client query keys define them once in a pure `<domain>-cache.ts`; queries, actions, hydration, query options, and hooks import from it.
- [ ] Feature-local client-support files sit in the smallest fitting place: query options at the feature root, `use-*` hook wrappers in `hooks/`, leaf components in `components/`, and shared support only after real cross-feature reuse.
- [ ] `'use client'` components are leaves — they import actions/hooks/providers, not async server components. A client component that needs server data has a server half in the feature (`ComposePanel` → `ComposePanelClient`); no page or layout creates query promises for it.
- [ ] Client leaves use `useOptimistic`, transitions, reducers, URL state, or form actions for interaction; they do not call `setState` in effects for derived React state.
- [ ] Forms whose action can reject input keep what the user typed: the action state returns the submitted values and the fields read them as `defaultValue`.
- [ ] Mutations validate their input and invalidate the affected data.

## Reference index

- **`references/feature-folders.md`** — where code goes: folder layout, cache contracts, naming, and merging sub-concepts.
- **`references/queries-actions.md`** — query/action rules: server-only, dedup, validation, invalidation, return shape.
- **`references/components.md`** — server/client boundary, skeletons, `use()`, single-use helpers, live data.
- **`references/pages-suspense.md`** — page composition, `params.then()`, Suspense placement, CLS, error boundaries.
- **`references/instant-navigation.md`** — prefetching decisions: `prefetch={true}`, the three render stages and their gates, validating what a navigation shows, hidden routes.
- **`references/cache-components.md`** — the `cacheComponents` decisions: which reads to cache, which directive to use, how to invalidate.
- **`references/single-page-applications.md`** — client cache decisions: placement, server seeding, Cache Components coordination, hydration, and mutations.
- **`references/ux-patterns.md`** — interaction decisions: optimistic vs pending vs inline error, toasts, action-prop, confirmations.
- **`references/testing.md`** — end-to-end tests: asserting the loading sequence with `instant()`, locating content across hidden routes, testing mutations.
- **`references/example.md`** — the next-beats reference app: invariant → file map, for seeing any rule in real code.

© aurorascharff · MIT · aurorascharff/nextjs-app-architecture-skill

Похожие скиллы

Всё по теме «Фронтенд и UI» →
nextjs-architecture-expert davila7 Субагент для Claude, который разбирает архитектуру Next.js: App Router, Server Components, миграцию и производительность. 4 935установок nextjs-app-router-fundamentals wsimmonds Скилл ведёт агента по Next.js App Router: перенос с Pages Router, вложенные layout, метаданные, динамические маршруты. Пригодится при переходе на app/. CX Codex +1 2 200установок nextjs-cache-architecture mohamed-hossam1 Выстраивает архитектуру кеширования для Next.js 16+ App Router. Помогает внедрить директиву "use cache", собрать типизированный реестр тегов и настроить границы Suspense. CX Codex +1 5 000установок nextjs-app-router-patterns Seth Hobson Помогает строить приложения на Next.js App Router: выбирать режим рендеринга, организовывать маршруты и получать данные. Подойдёт при миграции с Pages Router или работе с Server Components. CX Codex 32 529установок nextjs-app-router giuseppe-trisciuoglio Даёт паттерны и примеры для Next.js 16+ с App Router: от Server Components до route.ts и кэширования. CX Codex +1 3 900установок nextjs-app-router-cursorrules-prompt-file PatrickJS Правило для Cursor, которое задаёт агенту привычки Next.js App Router: серверные компоненты по умолчанию, файловый роутинг, отдельные файлы для загрузки и ошибок. ★ 41 011звёзд репо

Спонсоры проекта

Компании, которые помогают держать аналитику открытой