# Next.js Naming Conventions Standard

> **Scope:** frontend/nextjs/naming-conventions
> **Layer:** 1 (always)
> **Keywords:** naming, conventions, file names, component names, hooks, typescript
> **Load When:** creating any new file in a Next.js project

**Verified against:** Next.js 15 + Zod 4. Last-verified: 2026-05-20.

---

Consistent naming prevents filesystem bugs (Linux case-sensitivity) and keeps the codebase predictable.

## Core Rules

- ALWAYS use kebab-case for file names — never PascalCase or camelCase
- ALWAYS use PascalCase for React component exports
- ALWAYS use camelCase starting with `use` for hook exports
- ALWAYS suffix schema files with `.schemas.ts` and type files with `.types.ts`
- NEVER mix cases in the same category — no `UserCard.tsx` alongside `user-profile.tsx`

## Complete Reference Table

| Artifact | File Name | Export Name | Example |
|----------|-----------|-------------|---------|
| React Component | `user-card.tsx` | `UserCard` | `export function UserCard()` |
| Client Component | `user-form.tsx` | `UserForm` | `export function UserForm()` + `'use client'` |
| TanStack Query hook | `use-users.ts` | `useUsers` | `export function useUsers()` |
| Mutation hook | `use-create-user.ts` | `useCreateUser` | `export function useCreateUser()` |
| Utility hook | `use-debounce.ts` | `useDebounce` | `export function useDebounce()` |
| Zod schema file | `user.schemas.ts` | `createUserSchema` | `export const createUserSchema = z.object(...)` |
| TypeScript types | `user.types.ts` | `User`, `CreateUserInput` | `export type User = z.infer<typeof userSchema>` |
| Feature index | `index.ts` | (re-exports) | `export { UserCard } from './components/user-card'` |
| Page file | `page.tsx` | `default` | `export default function UsersPage()` |

## Hook Naming Rules

```
GET list:    use-users.ts          → useUsers()
GET single:  use-user.ts           → useUser(id: string)
POST:        use-create-user.ts    → useCreateUser()
PUT/PATCH:   use-update-user.ts    → useUpdateUser()
DELETE:      use-delete-user.ts    → useDeleteUser()
```

## Schema and Type Naming Rules

```typescript
// user.schemas.ts
export const userSchema = z.object({ id: z.string(), name: z.string() });
export const createUserSchema = z.object({ name: z.string().min(2), email: z.email() });
export const updateUserSchema = createUserSchema.partial();

// user.types.ts — derive from schemas, don't duplicate
export type User = z.infer<typeof userSchema>;
export type CreateUserInput = z.infer<typeof createUserSchema>;
export type UpdateUserInput = z.infer<typeof updateUserSchema>;
```

## Common Mistakes

| Wrong | Right | Why |
|-------|-------|-----|
| `UserCard.tsx` | `user-card.tsx` | Linux servers are case-sensitive |
| `useUsers.ts` | `use-users.ts` | Inconsistent with Next.js file conventions |
| `export default function UserCard` | `export function UserCard` | Named exports are more refactor-safe |
| `type User = { id: string }` | `type User = z.infer<typeof userSchema>` | Single source of truth |

---

*MORPH-SPEC by Polymorphism Tech*
