A Next.js 16 project set up with Tailwind CSS v4, shadcn/ui, and Biome. Code is organized around feature-based + atomic (atoms) structure, with hooks (React Query) separated from controllers (state + logic).
- Next.js 16.1.6 – React framework with App Router
- React 19.2.3 – UI library
- TypeScript 5 – Type safety
- Tailwind CSS v4 – Utility-first CSS framework
- shadcn/ui – Component library (atoms)
- TanStack React Query – Data fetching & mutations
- Biome – Fast linter and formatter
npm installIf you hit npm cache permission issues:
npm install --cache ./.npm-cache# Run development server
npm run dev
# Build for production
npm run build
# Run production server
npm run start
# Lint with Biome
npm run lint
# Lint and auto-fix
npm run lint:fix
# Format code
npm run format
# Type check
npm run type-checksrc/
├── app/ # Next.js App Router
│ ├── error.tsx # Error boundary (fallback UI on error)
│ ├── globals.css
│ ├── layout.tsx
│ ├── page.tsx
│ └── providers.tsx # QueryClientProvider (TanStack Query)
├── components/ # Shared components
│ ├── ui/ # Atoms (shadcn) – add: npx shadcn@latest add button input
│ └── shared/ # Shared molecules/organisms
├── features/ # Feature-based modules
│ └── user/
│ ├── components/ # UserTable, UserForm, UserManagement
│ ├── controllers/ # useUserController – state + logic (submit, error)
│ ├── hooks/ # useUsers, useCreateUser (React Query)
│ │ └── user.mock.ts # Mock data (can be swapped for real API later)
│ ├── schemas/ # Zod validation (user.schema)
│ ├── types/ # User, CreateUserInput
│ └── index.ts # Re-export feature
├── hooks/ # App-wide shared hooks
├── lib/
│ └── utils.ts # Re-export cn (shadcn)
├── services/ # Shared API client / auth (optional)
├── types/ # Shared types
└── utils/
└── cn.ts # cn() for Tailwind
| Layer | Role |
|---|---|
| components/ui/ | Atoms (shadcn): Button, Input, Table… |
| components/shared/ | Components shared across features (DataTable, Modal…) |
| features/*/hooks/ | React Query: useQuery, useMutation – data only |
| features/*/controllers/ | useState, logic, submit handlers – use hooks, expose to components |
| features/*/components/ | Feature UI: receive props from controller (or context later) |
| hooks/ (root) | App-wide hooks; feature-specific hooks live in features/*/hooks |
Add components to src/components/ui/:
npx shadcn@latest add button input table- Lint & format:
npm run lint,npm run format - Config:
biome.json - Format on save: configured in
.vscode/settings.json(requires Biome extension)
- ✅ Next.js 16 with App Router
- ✅ TypeScript
- ✅ Tailwind CSS v4
- ✅ shadcn/ui components
- ✅ TanStack React Query
- ✅ Feature-based structure with clear controller/hooks split
- ✅ Biome linter & formatter
- ✅ Error boundary (
app/error.tsx) - ✅ Path aliases (
@/)
- Tailwind CSS v4 uses CSS-first configuration; no
tailwind.config.jsneeded. - Mock data lives in
features/user/hooks/user.mock.ts; you can later switch to real API calls in the same hooks. - Error boundary: when a component throws, Next.js renders
error.tsxwith a “Try again” button.