Next js Development Setup
Next.js 14 setup: app-dir conventions, TypeScript, ESLint and Prettier configuration, dev vs production builds, and deployment best practices.
Introduction
This guide covers the complete setup for Next.js development including project creation (App Router), ESLint, Prettier, Husky + lint-staged, and TypeScript support. Use this as a reference when bootstrapping new applications or standardizing team tooling.
TL;DR
Bootstrap with the App Router + TypeScript, enable ESLint and Prettier, add Husky + lint-staged for pre-commit checks, and use `pnpm` for faster installs. CI should run `tsc --noEmit`, `eslint` and `prettier --check`.
Prerequisites
Before starting, make sure you have:
- Node.js (v18.17 or higher required)
- npm, yarn, or pnpm(package manager)
- A code editor (VSCode recommended)
Check Versions
1node --version # Should be v18.17 or higher
2npm --version # Should be 9.x or higherStep 1 — Create Next.js Project
Create Project with create-next-app
1npx create-next-app@latest my-next-appConfiguration Prompts
You will be asked several questions (recommendations in parentheses):
- TypeScript: Yes
- ESLint: Yes
- Tailwind CSS: Yes (recommended)
- src/ directory: Yes (recommended)
- App Router: Yes (recommended)
Navigate & Test
1cd my-next-app
2
3npm run devOpen the app at http://localhost:3000.
Project Structure (App Router)
1my-next-app/
2├── public/ # Static assets
3├── src/
4│ ├── app/
5│ │ ├── layout.tsx # Root layout
6│ │ ├── page.tsx # Home page
7│ │ ├── globals.css # Global styles
8│ │ └── favicon.ico # Favicon
9├── .eslintrc.json # ESLint config (auto-generated)
10├── next.config.js # Next.js config
11├── package.json # Dependencies
12├── tsconfig.json # TypeScript config
13└── tailwind.config.ts # Tailwind configStep 2 — Understanding Next.js ESLint Configuration
Auto-Generated ESLint Config
Next.js creates a minimal config:
1{
2 "extends": "next/core-web-vitals"
3}Extend with TypeScript and Custom Rules
1{
2 "extends": [
3 "next/core-web-vitals",
4 "next/typescript"
5 ],
6 "rules": {
7 "@typescript-eslint/no-unused-vars": "warn",
8 "@typescript-eslint/no-explicit-any": "warn",
9 "no-console": "warn",
10 "prefer-const": "error",
11 "react/jsx-curly-brace-presence": ["warn", { "props": "never", "children": "never" }],
12 "react/self-closing-comp": ["warn", { "component": true, "html": true }]
13 }
14}Next.js Specific ESLint Rules
Examples: @next/next/no-html-link-for-pages,@next/next/no-img-element, and@next/next/no-sync-scripts. Prefer Next.js components (`Link`, `Image`, `Script`) where applicable.
Add ESLint Scripts
1{
2 "scripts": {
3 "dev": "next dev",
4 "build": "next build",
5 "start": "next start",
6 "lint": "next lint",
7 "lint:fix": "next lint --fix"
8 }
9}Test ESLint
1npm run lintStep 3 — Configure Prettier for Next.js
Install Prettier
1npm install --save-dev prettier eslint-config-prettierCreate .prettierrc
1{
2 "semi": true,
3 "singleQuote": true,
4 "tabWidth": 2,
5 "useTabs": false,
6 "trailingComma": "es5",
7 "printWidth": 100,
8 "arrowParens": "always",
9 "endOfLine": "lf",
10 "bracketSpacing": true,
11 "bracketSameLine": false,
12 "jsxSingleQuote": false,
13 "plugins": ["prettier-plugin-tailwindcss"]
14}Install Tailwind Prettier Plugin
1npm install --save-dev prettier-plugin-tailwindcssCreate .prettierignore
1# Dependencies
2node_modules/
3
4# Build outputs
5.next/
6out/
7dist/
8
9# Cache
10.cache/
11.turbo/
12
13# Logs
14*.log
15
16# Environment files
17.env*.localIntegrate Prettier with ESLint
1{
2 "extends": [
3 "next/core-web-vitals",
4 "next/typescript",
5 "prettier"
6 ],
7 "rules": {
8 "@typescript-eslint/no-unused-vars": "warn",
9 "@typescript-eslint/no-explicit-any": "warn",
10 "no-console": "warn",
11 "prefer-const": "error"
12 }
13}VSCode Settings
1{
2 "editor.defaultFormatter": "esbenp.prettier-vscode",
3 "editor.formatOnSave": true,
4 "editor.codeActionsOnSave": {
5 "source.fixAll.eslint": "explicit",
6 "source.organizeImports": "explicit"
7 },
8 "[typescript]": {
9 "editor.defaultFormatter": "esbenp.prettier-vscode"
10 },
11 "[typescriptreact]": {
12 "editor.defaultFormatter": "esbenp.prettier-vscode"
13 },
14 "[javascript]": {
15 "editor.defaultFormatter": "esbenp.prettier-vscode"
16 },
17 "[javascriptreact]": {
18 "editor.defaultFormatter": "esbenp.prettier-vscode"
19 },
20 "[json]": {
21 "editor.defaultFormatter": "esbenp.prettier-vscode"
22 }
23}Add Prettier Scripts
1{
2 "scripts": {
3 "dev": "next dev",
4 "build": "next build",
5 "start": "next start",
6 "lint": "next lint",
7 "lint:fix": "next lint --fix",
8 "format": "prettier --write "src/**/*.{ts,tsx,css,json}"",
9 "format:check": "prettier --check "src/**/*.{ts,tsx,css,json}""
10 }
11}Step 4 — Setup Husky and lint-staged
Install & Initialize
1npm install --save-dev husky lint-staged
2
3npx husky initConfigure lint-staged
1{
2 "lint-staged": {
3 "*.{ts,tsx}": [
4 "eslint --fix --max-warnings=0",
5 "prettier --write"
6 ],
7 "*.{css,json}": [
8 "prettier --write"
9 ]
10 }
11}Create Pre-Commit Hook
1#!/usr/bin/env sh
2. "$(dirname -- "$0")/_/husky.sh"
3
4npx lint-stagedUpdate package.json Scripts
1{
2 "scripts": {
3 "dev": "next dev",
4 "build": "next build",
5 "start": "next start",
6 "lint": "next lint",
7 "lint:fix": "next lint --fix",
8 "format": "prettier --write "src/**/*.{ts,tsx,css,json}"",
9 "format:check": "prettier --check "src/**/*.{ts,tsx,css,json}"",
10 "prepare": "husky install"
11 }
12}Next.js Best Practices
App Router File Conventions
Use `layout.tsx`, `page.tsx`, `loading.tsx`, `error.tsx`, and `not-found.tsx` in your app route folders. Keep server components by default and add use client only when necessary.
Server vs Client Components
1// Server Component (default)
2export default function Page() {
3 // runs on the server
4 return <div>Server Component</div>
5}
6
7// Client Component
8'use client'
9import { useState } from 'react'
10export default function Counter() {
11 const [count, setCount] = useState(0)
12 return <button onClick={() => setCount(count + 1)}>{count}</button>
13}Image Optimization
1import Image from 'next/image'
2
3<Image src="/hero.jpg" alt="Hero" width={1200} height={600} priority />Metadata & SEO
1import { Metadata } from 'next'
2
3export const metadata: Metadata = {
4 title: 'Home | My Next.js App',
5 description: 'Welcome to my Next.js application'
6}Quick verification
1# Check node and package manager
2 node --version
3 pnpm --version
4
5 # Start dev server
6 pnpm dev # (or npm run dev)
7
8 # Lint and format checks
9 pnpm exec eslint .
10 pnpm exec prettier --check "src/**/*.{ts,tsx,css,json}"Complete Setup Checklist
- Node.js v18.17+ installed
- Project created with `create-next-app`
- App Router & TypeScript selected
- ESLint and Prettier configured
- Husky + lint-staged installed and tested
Useful Commands
1# Start development server
2npm run dev
3
4# Build for production
5npm run build
6
7# Start production server
8npm run start
9
10# Lint
11npm run lint
12
13# Format
14npm run formatTroubleshooting
Common issues and fixes: missing plugins (run `npm install`), image optimization errors (add width/height or configure remote domains in `next.config.js`), and hydration mismatches (move browser-only code to client components).