SSG (Static Site Generation) pre-renders pages at build time and serves the same HTML to all users. Ideal for content that doesn't change frequently. SSR renders pages on-demand for each request, providing fresh data. Choose SSG for performance and SSR for dynamic content. ISR (Incremental Static Regeneration) combines both by revalidating static pages periodically.
Next.js uses file-based routing: files in the app or pages directory automatically become routes. Dynamic routes use brackets: [id].tsx creates /posts/123. Catch-all routes use [...slug].tsx to match any path. Optional catch-all: [[...slug]].tsx. Dynamic routes access parameters via useRouter() or params prop. This is simpler than manual routing.
getStaticProps generates static pages at build time. It fetches data from APIs or databases and passes it as props. Use it for content that doesn't change frequently (blog posts, documentation). You can revalidate pages with ISR using the revalidate key. getStaticProps only runs on the server during build, not on the client.
API routes let you create backend endpoints without a separate server. Create files in pages/api or app/api. Each file becomes an endpoint. Handle requests with HTTP methods (GET, POST, etc.). You can access query params and request body. API routes are useful for authentication, database queries, and external API calls while keeping your code co-located.
Next.js Image component optimizes images automatically: lazy loads by default, responsive sizing, modern formats (WebP), prevents layout shift. Use <Image src={} alt={} width={} height={} /> instead of <img>. The Image component calculates responsive sizes and generates multiple versions. Images are optimized on-demand and cached by default.
Middleware runs before requests are processed, useful for authentication, redirects, and headers. Create middleware.ts in the root directory and export a middleware function. Use matchers to specify which routes it applies to. Middleware runs on the edge for low latency. Common use: check auth tokens and redirect unauthorized users.
Next.js automatically code splits at the page level, loading only required JavaScript. Use dynamic() to lazy load components. dynamic(() => import('./Component')) imports the component only when needed, showing a fallback during loading. This reduces initial bundle size and improves performance for large apps.
The app router (App Directory) is the newer approach using nested layouts, server components by default, and cleaner organization. The pages router is the older approach with pages directly mapping to routes. App router provides better organization, layout sharing, and server components. New projects should use the app router.
Use middleware to protect routes, getServerSideProps to check auth server-side, or client-side checks with useEffect. Libraries like NextAuth.js simplify OAuth integration. Store tokens in secure httpOnly cookies. Combine server-side and client-side validation. NextAuth.js is recommended for production apps.
Server components (marked with 'use server') run only on the server, reducing bundle size and allowing direct database access. They render HTML on the server sent to the client. Use them for data fetching, keeping secrets secure, and reducing JavaScript. Client components ('use client') run in the browser for interactivity. Use server components by default.