Skip to content
Skill · Cursor.cursorrulesCoding

Next.js + React + TypeScript House Style

Opinionated App Router conventions covering server/client component boundaries, suspense, data fetching, and file naming.

Use when: Drop into any Next.js 14+ App Router project with TypeScript to keep generated code aligned with server-first React conventions.

@libraryNewcomer
0 upvotes0 forks0 comments

The skill file

Cursor · .cursorrules
.cursorrules2876 chars
You are working in a Next.js App Router project with React 19 and strict TypeScript. ## Component boundaries - Every component is a Server Component unless it uses state, effects, refs, or browser APIs. Only then add `"use client"` — and add it to the smallest leaf component possible, never to a page or layout. - Never pass functions, class instances, or Dates as props across the server/client boundary. Serialize to primitives or move the logic server-side. - Pages (`page.tsx`) and layouts (`layout.tsx`) stay server components, always. If a page needs interactivity, extract a client child. - Co-locate route-private components in a `_components/` folder inside the route segment. Shared components live in `src/components/`. ## Data fetching - Fetch in Server Components with `async`/`await` directly in the component body. Never fetch in a `useEffect`. - Parallelize independent fetches: start promises first, then `await Promise.all([...])`. Sequential awaits for independent data are a bug. - Wrap slow data branches in `<Suspense fallback={<XSkeleton />}>` with a dedicated skeleton component, not a generic spinner. One Suspense boundary per independent data region. - Mutations go through Server Actions (`"use server"`) validated with Zod at the top of the action. Call `revalidatePath`/`revalidateTag` after every write; never rely on client-side refetch. - Use `useActionState` for form pending/error state. Do not hand-roll `isSubmitting` booleans. ## Components and naming - `const` arrow components with named exports: `export const UserCard = (props: UserCardProps) => {...}`. Default exports only where Next.js requires them (`page`, `layout`, `error`, `loading`, `not-found`). - Props types are named `<Component>Props` and declared directly above the component. Use `type`, not `interface`, unless declaration merging is required. - Files are kebab-case (`user-card.tsx`); components are PascalCase. One exported component per file. - Event handler props are `onX`; the handler implementations are `handleX`. ## TypeScript - No `any`, no non-null assertions (`!`), no `as` casts except `as const`. If a type is unknown, narrow it with a type guard. - Type `searchParams` and `params` as Promises and `await` them (Next 15 behavior). Validate `searchParams` with Zod before use. - Derive types from runtime sources: `z.infer<typeof schema>`, `ReturnType<typeof fn>` — do not duplicate shapes by hand. ## Things to never do - No `useEffect` for derived state, data fetching, or syncing props to state. - No `router.push` for links — use `<Link>`; reserve imperative navigation for post-mutation redirects. - No `<img>`; use `next/image` with explicit `width`/`height` or `fill`. - No barrel files (`index.ts` re-export hubs) — they break tree-shaking and slow the dev server. - No `process.env` access outside a single validated `env.ts` module.

Install

drop into your repo

Save this to your project or home directory so Cursor can load it.

path./.cursorrules
Discussion

What people are saying

Forks

0 forks of this skill
Loading forks…