Skip to main content

Basics

Fundamentals of Next.js, project setup, configuration, and core concepts for building React applications.

Getting Started

Installation and Setup

# Create a new Next.js app
npx create-next-app@latest my-app
npx create-next-app@latest my-app --typescript
npx create-next-app@latest my-app --tailwind

# With specific options
npx create-next-app@latest my-app --typescript --tailwind --eslint --app --src-dir --import-alias "@/*"

# Navigate to project
cd my-app

# Start development server
npm run dev
# or
yarn dev
# or
pnpm dev

Manual Installation

# Create new project
mkdir my-nextjs-app
cd my-nextjs-app
npm init -y

# Install Next.js and React
npm install next react react-dom

# Install TypeScript (optional)
npm install --save-dev typescript @types/react @types/node

# Install ESLint (optional)
npm install --save-dev eslint eslint-config-next

Package.json Scripts

{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"type-check": "tsc --noEmit"
}
}

Project Structure

App Router Structure (Next.js 13+)

my-app/
├── app/
│ ├── layout.tsx # Root layout
│ ├── page.tsx # Home page
│ ├── loading.tsx # Loading UI
│ ├── error.tsx # Error UI
│ ├── not-found.tsx # 404 page
│ ├── globals.css # Global styles
│ ├── about/
│ │ └── page.tsx # /about route
│ ├── blog/
│ │ ├── page.tsx # /blog route
│ │ └── [slug]/
│ │ └── page.tsx # /blog/[slug] route
│ └── api/
│ └── users/
│ └── route.ts # API route
├── components/
│ ├── ui/
│ └── shared/
├── lib/
├── public/
├── styles/
├── next.config.js
├── package.json
└── tsconfig.json

Pages Router Structure (Legacy)

my-app/
├── pages/
│ ├── _app.tsx # App component
│ ├── _document.tsx # Document component
│ ├── index.tsx # Home page
│ ├── about.tsx # /about route
│ ├── blog/
│ │ ├── index.tsx # /blog route
│ │ └── [slug].tsx # /blog/[slug] route
│ └── api/
│ └── users.ts # API route
├── components/
├── lib/
├── public/
├── styles/
├── next.config.js
├── package.json
└── tsconfig.json

Next.js Configuration

next.config.js

/** @type {import('next').NextConfig} */
const nextConfig = {
// Enable experimental features
experimental: {
appDir: true,
serverActions: true,
serverComponentsExternalPackages: ['sequelize'],
},

// Image optimization
images: {
domains: ['example.com', 'images.unsplash.com'],
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
formats: ['image/webp', 'image/avif'],
},

// Redirects
async redirects() {
return [
{
source: '/old-page',
destination: '/new-page',
permanent: true,
},
];
},

// Rewrites
async rewrites() {
return [
{
source: '/api/:path*',
destination: 'https://api.example.com/:path*',
},
];
},

// Headers
async headers() {
return [
{
source: '/:path*',
headers: [
{
key: 'X-Custom-Header',
value: 'my-custom-value',
},
],
},
];
},

// Environment variables
env: {
CUSTOM_KEY: 'value',
},

// Build output
output: 'standalone', // or 'export'

// Webpack configuration
webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
// Custom webpack config
return config;
},

// TypeScript configuration
typescript: {
ignoreBuildErrors: false,
},

// ESLint configuration
eslint: {
ignoreDuringBuilds: false,
},
};

module.exports = nextConfig;

TypeScript Configuration

{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "es6"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@/components/*": ["./components/*"],
"@/lib/*": ["./lib/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}

Core Concepts

App Router (Next.js 13+)

// app/layout.tsx - Root Layout
import './globals.css';
import { Inter } from 'next/font/google';

const inter = Inter({ subsets: ['latin'] });

export const metadata = {
title: 'My App',
description: 'Generated by create next app',
};

export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body className={inter.className}>
<header>
<nav>Navigation</nav>
</header>
<main>{children}</main>
<footer>Footer</footer>
</body>
</html>
);
}
// app/page.tsx - Home Page
export default function HomePage() {
return (
<div>
<h1>Welcome to Next.js</h1>
<p>This is the home page</p>
</div>
);
}
// app/about/page.tsx - About Page
export default function AboutPage() {
return (
<div>
<h1>About Us</h1>
<p>This is the about page</p>
</div>
);
}

Pages Router (Legacy)

// pages/_app.tsx - App Component
import type { AppProps } from 'next/app';
import '../styles/globals.css';

export default function App({ Component, pageProps }: AppProps) {
return (
<div>
<header>
<nav>Navigation</nav>
</header>
<main>
<Component {...pageProps} />
</main>
<footer>Footer</footer>
</div>
);
}
// pages/index.tsx - Home Page
import Head from 'next/head';

export default function HomePage() {
return (
<>
<Head>
<title>My App</title>
<meta name="description" content="Generated by create next app" />
</Head>
<div>
<h1>Welcome to Next.js</h1>
<p>This is the home page</p>
</div>
</>
);
}

Environment Variables

.env Files

# .env.local (local development)
DATABASE_URL=localhost:5432
API_KEY=your-api-key
NEXTAUTH_SECRET=your-secret

# .env.production (production)
DATABASE_URL=production-db-url
API_KEY=production-api-key

# .env (all environments)
NEXT_PUBLIC_API_URL=https://api.example.com

Using Environment Variables

// Server-side only
const databaseUrl = process.env.DATABASE_URL;

// Client-side accessible (must start with NEXT_PUBLIC_)
const apiUrl = process.env.NEXT_PUBLIC_API_URL;

// In next.config.js
module.exports = {
env: {
CUSTOM_KEY: process.env.CUSTOM_KEY,
},
};

Built-in Components

import Link from 'next/link';

export default function Navigation() {
return (
<nav>
<Link href="/">Home</Link>
<Link href="/about">About</Link>
<Link href="/blog/hello-world">Blog Post</Link>

{/* Dynamic routes */}
<Link href={`/users/${userId}`}>User Profile</Link>

{/* Query parameters */}
<Link href="/search?q=nextjs">Search</Link>

{/* External links */}
<Link href="https://nextjs.org" target="_blank">
Next.js Docs
</Link>

{/* Programmatic navigation */}
<button onClick={() => router.push('/dashboard')}>
Go to Dashboard
</button>
</nav>
);
}

Image Component

import Image from 'next/image';

export default function ImageExample() {
return (
<div>
{/* Local images */}
<Image
src="/hero-image.jpg"
alt="Hero Image"
width={800}
height={600}
priority
/>

{/* Remote images */}
<Image
src="https://example.com/image.jpg"
alt="Remote Image"
width={500}
height={300}
placeholder="blur"
blurDataURL="data:image/jpeg;base64,..."
/>

{/* Responsive images */}
<Image
src="/responsive-image.jpg"
alt="Responsive Image"
fill
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
className="object-cover"
/>
</div>
);
}

Head Component (Pages Router)

import Head from 'next/head';

export default function SEOPage() {
return (
<>
<Head>
<title>Page Title</title>
<meta name="description" content="Page description" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />

{/* Open Graph */}
<meta property="og:title" content="Page Title" />
<meta property="og:description" content="Page description" />
<meta property="og:image" content="/og-image.jpg" />

{/* Twitter Card */}
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="Page Title" />
<meta name="twitter:description" content="Page description" />

{/* Custom styles */}
<style jsx>{`
.custom-class {
color: blue;
}
`}</style>
</Head>

<div>
<h1>SEO Optimized Page</h1>
<p>This page has proper SEO metadata</p>
</div>
</>
);
}

Development Tools

Next.js CLI Commands

# Development
npm run dev # Start development server
npm run dev -- -p 3001 # Start on different port

# Build
npm run build # Build for production
npm run start # Start production server

# Analysis
npm run build -- --analyze # Bundle analysis
npm run lint # Run ESLint
npm run type-check # TypeScript check

# Export static site
npm run build && npm run export

Development Features

// Hot reloading is automatic in development

// Error overlay shows detailed error information

// Fast refresh preserves React state during edits

// Automatic TypeScript compilation

// Built-in ESLint support

File-based Routing

Basic Routes

app/page.tsx              → /
app/about/page.tsx → /about
app/blog/page.tsx → /blog
app/blog/[slug]/page.tsx → /blog/hello-world

Dynamic Routes

// app/blog/[slug]/page.tsx
export default function BlogPost({ params }: { params: { slug: string } }) {
return <h1>Blog Post: {params.slug}</h1>;
}

// app/user/[id]/page.tsx
export default function UserProfile({ params }: { params: { id: string } }) {
return <h1>User ID: {params.id}</h1>;
}

Catch-all Routes

// app/docs/[...slug]/page.tsx
export default function DocsPage({ params }: { params: { slug: string[] } }) {
return <h1>Docs: {params.slug.join('/')}</h1>;
}

// Matches: /docs/getting-started, /docs/api/reference, etc.

Quick Reference

Essential Commands

  • npx create-next-app@latest - Create new Next.js app
  • npm run dev - Start development server
  • npm run build - Build for production
  • npm run start - Start production server
  • npm run lint - Run ESLint

Key Concepts

  • App Router - New routing system (Next.js 13+)
  • Pages Router - Legacy routing system
  • Server Components - React components that run on server
  • Client Components - React components that run on client
  • File-based Routing - Routes based on file structure

Built-in Components

  • <Link> - Client-side navigation
  • <Image> - Optimized images
  • <Head> - HTML head management (Pages Router)
  • <Script> - Script optimization

Configuration Files

  • next.config.js - Next.js configuration
  • tsconfig.json - TypeScript configuration
  • .env.local - Environment variables
  • package.json - Project dependencies and scripts

Best Practices

  • Use TypeScript for better development experience
  • Implement proper SEO with metadata
  • Optimize images with Next.js Image component
  • Use environment variables for configuration
  • Follow Next.js file and folder conventions
  • Enable ESLint for code quality