Next.js New Project Setup: Optimal Flow and Best Practices
Next.js New Project Setup: Optimal Flow and Best Practices
Starting a new Next.js project can be overwhelming with all the configuration options available. This guide will walk you through the optimal setup process, from initialization to production-ready configuration.
Step 1: Project Initialization
Create New Next.js Project
Use the official Next.js CLI to create a new project:
1# Create new Next.js app with TypeScript2npx create-next-app@latest my-app --typescript --tailwind --eslint --app3 4# Or with JavaScript5npx create-next-app@latest my-app --js --tailwind --eslint --appProject Structure
After initialization, your project should have this structure:
1my-app/2├── app/ # App Router (Next.js 13+)3│ ├── layout.js # Root layout4│ ├── page.js # Home page5│ └── globals.css # Global styles6├── public/ # Static assets7├── .next/ # Build output (gitignored)8├── node_modules/ # Dependencies (gitignored)9├── .eslintrc.json # ESLint config10├── .gitignore # Git ignore rules11├── next.config.js # Next.js config12├── package.json # Dependencies13├── postcss.config.js # PostCSS config14├── tailwind.config.js # Tailwind config15└── tsconfig.json # TypeScript config (if using TS)Step 2: Essential Configuration
Update next.config.js
Configure Next.js for optimal performance:
1/** @type {import('next').NextConfig} */2const nextConfig = {3 // Enable React strict mode4 reactStrictMode: true,5 6 // Optimize images7 images: {8 domains: ['example.com'],9 formats: ['image/avif', 'image/webp'],10 },11 12 // Compress output13 compress: true,14 15 // Enable standalone output for DockerStep 3: Optimal Folder Structure
Organize your project with this structure:
1my-app/2├── app/3│ ├── (auth)/ # Route group for auth pages4│ │ ├── login/5│ │ └── register/6│ ├── (dashboard)/ # Route group for dashboard7│ │ ├── layout.js8│ │ └── page.js9│ ├── api/ # API routes10│ │ └── users/11│ │ └── route.js12│ ├── layout.js # Root layout13│ ├── page.js # Home page14│ └── globals.css15├── components/Step 4: Install Essential Dependencies
Core Dependencies
1# Form handling2npm install react-hook-form zod @hookform/resolvers3 4# State management5npm install zustand # or redux toolkit6 7# HTTP client8npm install axios9 10# Date handling11npm install date-fns12 13# Icons14npm install react-icons15 Development Dependencies
1# Code formatting2npm install -D prettier prettier-plugin-tailwindcss3 4# Additional linting5npm install -D @typescript-eslint/eslint-plugin6 7# Testing8npm install -D jest @testing-library/react @testing-library/jest-dom9 10# Type checking (if using TypeScript)11npm install -D typescript @types/node @types/reactStep 5: Environment Variables Setup
Create environment variable files:
.env.local (for local development):
1# Database2DATABASE_URL=postgresql://user:password@localhost:5432/mydb3 4# API5NEXT_PUBLIC_API_URL=http://localhost:3000/api6 7# Authentication8NEXTAUTH_URL=http://localhost:30009NEXTAUTH_SECRET=your-secret-key10 11# Third-party services12STRIPE_PUBLIC_KEY=pk_test_...13GOOGLE_CLIENT_ID=....env.example (template for team):
1DATABASE_URL=2NEXT_PUBLIC_API_URL=3NEXTAUTH_URL=4NEXTAUTH_SECRET=Step 6: Configure ESLint and Prettier
.eslintrc.json
1{2 "extends": [3 "next/core-web-vitals",4 "prettier"5 ],6 "rules": {7 "react/no-unescaped-entities": "off",8 "@next/next/no-img-element": "warn"9 }10}.prettierrc
1{2 "semi": false,3 "singleQuote": true,4 "tabWidth": 2,5 "trailingComma": "es5",6 "printWidth": 100,7 "plugins": [8 "prettier-plugin-tailwindcss"9 ]10}.prettierignore
1.next2node_modules3public4*.min.jsStep 7: Set Up Root Layout
Update app/layout.js:
1import { Inter } from 'next/font/google'2import './globals.css'3import Header from '@/components/layout/Header'4import Footer from '@/components/layout/Footer'5 6const inter = Inter({ subsets: ['latin'] })7 8export const metadata = {9 title: 'My App',10 description: 'Description of my app',11 keywords: ['nextjs', 'react', 'web development'],12}13 14export default function RootLayout({ children }) {15 return (Step 8: Create Utility Functions
Create lib/utils.js:
1// Format date2export function formatDate(date) {3 return new Date(date).toLocaleDateString('en-US', {4 year: 'numeric',5 month: 'long',6 day: 'numeric',7 })8}9 10// Debounce function11export function debounce(func, wait) {12 let timeout13 return function executedFunction(...args) {14 const later = () => {15 clearTimeout(timeout)Step 9: Set Up API Routes
Create API route example app/api/users/route.js:
1import { NextResponse } from 'next/server'2 3export async function GET(request) {4 try {5 const users = await fetchUsers() // Your data fetching logic6 return NextResponse.json({ users })7 } catch (error) {8 return NextResponse.json(9 { error: 'Failed to fetch users' },10 { status: 500 }11 )12 }13}14 15export async function POST(request) {Step 10: Development Workflow
Package.json Scripts
Update package.json scripts:
1{2 "scripts": {3 "dev": "next dev",4 "build": "next build",5 "start": "next start",6 "lint": "next lint",7 "format": "prettier --write .",8 "format:check": "prettier --check .",9 "type-check": "tsc --noEmit",10 "test": "jest",11 "test:watch": "jest --watch"12 }13}Git Workflow
1. Create feature branch: git checkout -b feature/new-feature
2. Make changes: Write code, add tests
3. Format code: npm run format
4. Lint code: npm run lint
5. Commit: git commit -m "feat: add new feature"
6. Push: git push origin feature/new-feature
7. Create PR: Open pull request on GitHub
Step 11: Performance Optimization
Image Optimization
1import Image from 'next/image'2 3export default function MyComponent() {4 return (5 <Image6 src="/image.jpg"7 alt="Description"8 width={500}9 height={300}10 priority // For above-the-fold images11 placeholder="blur" // Optional12 />13 )14}Font Optimization
1import { Inter } from 'next/font/google'2 3const inter = Inter({4 subsets: ['latin'],5 display: 'swap',6 variable: '--font-inter',7})Code Splitting
Use dynamic imports for large components:
1import dynamic from 'next/dynamic'2 3const HeavyComponent = dynamic(() => import('@/components/HeavyComponent'), {4 loading: () => <p>Loading...</p>,5 ssr: false, // Disable SSR if needed6})Step 12: Testing Setup
Jest Configuration
Create jest.config.js:
1const nextJest = require('next/jest')2 3const createJestConfig = nextJest({4 dir: './',5})6 7const customJestConfig = {8 setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],9 testEnvironment: 'jest-environment-jsdom',10}11 12module.exports = createJestConfig(customJestConfig)Example Test
1import { render, screen } from '@testing-library/react'2import Home from '@/app/page'3 4describe('Home', () => {5 it('renders heading', () => {6 render(<Home />)7 const heading = screen.getByRole('heading', {8 name: /welcome/i,9 })10 expect(heading).toBeInTheDocument()11 })12})Best Practices Summary
1. **Use TypeScript**
TypeScript catches errors early and improves developer experience.
2. **Follow File Naming Conventions**
3. **Optimize Images**
Always use Next.js Image component for better performance.
4. **Use Server Components**
Prefer Server Components when possible for better performance.
5. **Implement Error Boundaries**
Handle errors gracefully with error boundaries.
6. **Add Loading States**
Use loading.tsx files for better UX.
7. **Environment Variables**
Never commit sensitive data. Use .env.local for secrets.
8. **Code Organization**
Keep components small and focused. Use feature-based folder structure.
Conclusion
Following this setup guide will give you a solid foundation for your Next.js project. Remember to:
Your Next.js project is now ready for development!
Enjoyed this article?
Support our work and help us create more free content for developers.
Stay Updated
Get the latest articles and updates delivered to your inbox.