What is Next.js? Basic
React is a JavaScript library for building user interfaces out of small reusable pieces called components. On its own, React only handles the UI. It does not handle routing, servers, SEO or bundling.
Next.js is a React framework. It adds everything a real website needs on top of React: file-based routing, server rendering, an API/backend layer, image and font optimization, and a build system.
How a page reaches the user
Hydration means React "attaches" to the HTML the server sent, so it becomes interactive.
SEO friendly
Search engines get real HTML instead of an empty <div>.
Fast
Server rendering, code-splitting and caching are built in.
Full stack
Frontend and backend live in one project, one language.
Setup & your first project Basic
Prerequisites
- Install Node.js (LTS)Download it from nodejs.org. Check the install with
node -vandnpm -v. - Install a code editorVS Code is recommended. Add the ES7+ React snippets and Prettier extensions.
- Know basic HTML, CSS and JavaScriptMainly variables, functions, arrays, objects,
map(), arrow functions,async/awaitand modules.
Create the app
| Command | What it does | When to use |
|---|---|---|
npm run dev | Development server with hot reload | While coding |
npm run build | Builds an optimized production version | Before deploying |
npm run start | Runs the production build | On the server |
npm run lint | Checks code for problems | Before committing |
Project structure Basic
In the App Router, the app/ folder is the heart of your project. Every folder inside it can become a URL segment.
- my-app/
- app/ ← routes live here
- layout.tsx ← root layout (html, body), wraps every page
- page.tsx ← the "/" home page
- globals.css ← global styles
- about/
- page.tsx ← "/about"
- api/
- route.ts ← backend endpoint (see Backend notes)
- components/ ← reusable UI pieces (Navbar, Card…)
- lib/ ← helpers, db client, utils
- public/ ← static files served at "/" (images, favicon)
- next.config.ts ← Next.js configuration
- package.json ← dependencies + scripts
- tsconfig.json ← TypeScript settings
- .env.local ← secrets (never commit!)
- app/ ← routes live here
page.tsx (UI) or route.ts (API). That means you can safely put components inside app/ too.JSX, components & props Basic
A component is a function that returns UI. That UI is written in JSX, a syntax that looks like HTML but lives inside JavaScript.
Data flows down the tree through props.
JSX rules to remember
| HTML | JSX | Why |
|---|---|---|
class="btn" | className="btn" | class is a reserved word in JS |
for="email" | htmlFor="email" | for is reserved too |
onclick="..." | onClick={fn} | Events use camelCase and take a function |
style="color:red" | style={{ color: "red" }} | Style is an object |
<img> | <img /> | Every tag must be closed |
| Many root elements | One root or <>...</> | A component returns a single element (a Fragment is fine) |
File-based routing Basic
In Next.js you don't write a router config. The folder structure is the router. Each folder is a URL segment, and a page.tsx file makes that segment visible.
Special files in a route folder
page.tsx
The UI for that URL. Makes the route public.
layout.tsx
A shared wrapper (navbar, sidebar). It stays mounted when you navigate between pages.
loading.tsx
Shown instantly while the page loads its data.
error.tsx
Catches errors in that segment and shows a fallback UI.
not-found.tsx
A custom 404 page.
route.ts
An API endpoint (GET, POST…). Covered on the Backend page.
You created app/contact/ContactForm.tsx. Is /contact now a page?
Layouts Basic
A layout wraps pages and keeps its state when you navigate. Layouts nest: the root layout wraps the dashboard layout, which wraps the dashboard pages.
layout.tsx is kept alive between navigations, so its state survives. template.tsx has the same shape but is re-created on every navigation. Use it when you want an animation or effect to run again on each page.Styling: CSS, CSS Modules & Bootstrap Basic
Global CSS
globals.css is imported once in the root layout and applies everywhere.
CSS Modules
Button.module.css: class names are scoped to one component, so they never clash.
Bootstrap
Ready-made grid and components. Install it with npm and import the CSS in the layout.
Adding Bootstrap to Next.js
- Install
npm install bootstrap bootstrap-icons - Import the CSS in the root layout
import "bootstrap/dist/css/bootstrap.min.css"; - Load Bootstrap's JS on the client onlyDropdowns, modals and other interactive components need JS. Bootstrap's JS uses
document, so it must load in the browser.
CSS Modules example
py-5, d-flex, row) for layout, and CSS Modules for anything custom.Images, fonts & metadata Basic
next/image
The <Image> component resizes images, lazy-loads them, serves modern formats like WebP/AVIF, and reserves space so the layout doesn't jump.
next/font
Metadata (SEO)
Server vs Client Components Intermediate
This is the most important concept in the App Router. Every component is a Server Component by default. You opt in to a Client Component by adding "use client" at the very top of the file.
Server Component (default)
- Runs only on the server
- Can be
asyncandawaitdata directly - Can read the database and secrets safely
- Zero JS is sent to the browser for it
- ✗ No
useState,useEffectoronClick
Client Component
- Starts with
"use client" - Pre-rendered on the server, then hydrated in the browser
- Can use state, effects and event handlers
- Can use browser APIs (
window,localStorage) - ✗ Never put secrets or DB calls here
Only the interactive pieces ship JavaScript. Everything else stays on the server.
- A Client Component cannot import a Server Component. It can receive one as
childrenor another prop. - Props passed from server to client must be serializable: strings, numbers, plain objects and arrays. Functions are not allowed, except Server Actions.
"use client"marks a boundary. Everything that file imports also becomes client code.
A component uses onClick. What must you add?
React hooks essentials Intermediate
Hooks are functions that start with use and let Client Components have state and side effects. Call them at the top level of a component, never inside if-statements or loops.
| Hook | Purpose | Analogy |
|---|---|---|
useState | Remember a value and re-render when it changes | A whiteboard that redraws the room when edited |
useEffect | Sync with outside systems after render | "After you finish painting, turn on the lights" |
useRef | Mutable box; access DOM nodes | A sticky note that doesn't trigger a redraw |
useMemo / useCallback | Cache a value / a function between renders | Remembering a calculation's answer |
useContext | Read shared data without prop drilling | See the React Context page |
useReducer | Complex state with actions | A mini Redux (see the React page) |
useEffect makes the effect run after every render. If the effect also sets state, you get an infinite loop.Dynamic routes & params Intermediate
| Folder | Matches | params |
|---|---|---|
app/blog/[slug] | /blog/hello | { slug: "hello" } |
app/shop/[...parts] | /shop/men/shoes/nike | { parts: ["men","shoes","nike"] } |
app/docs/[[...parts]] | /docs and /docs/a/b | { parts: undefined | [...] } |
useParams() and useSearchParams() from next/navigation. Inside a client component you can also unwrap the params Promise with React's use(params).Loading, error & not-found UI Intermediate
Next.js wraps your page in React boundaries automatically, based on these special files:
Data fetching Intermediate
In the App Router, the simplest approach is to fetch in a Server Component with async/await. You don't need useEffect or a loading state for this.
Sequential (waterfall) — slow
Parallel (Promise.all) — fast
Fetching on the client (when needed)
Fetch in the browser for data that depends on user interaction or changes very often, such as live search or polling. Use a library like SWR or TanStack Query. They handle caching, retries and revalidation for you.
Forms & Server Actions Intermediate
A Server Action is an async function marked with "use server". You can pass it straight to a form's action. Next.js turns it into a POST request behind the scenes, so you don't have to write an API route.
Rendering strategies Advanced
The main question is when the HTML gets built. Next.js chooses the strategy per route, based on what your code uses.
| Strategy | HTML built | Best for | How in App Router |
|---|---|---|---|
| SSG Static | Once, at build | Marketing pages, docs, blogs | Default when no dynamic APIs are used |
| ISR Incremental | At build, then re-built in the background | Product pages, news | export const revalidate = 60 |
| SSR Dynamic | On every request | Dashboards, personalised pages | Using cookies(), headers() or searchParams, or cache: "no-store" |
| CSR Client | In the browser | Highly interactive widgets | "use client" + SWR / useEffect |
| Streaming | In chunks | Pages with some slow parts | <Suspense> / loading.tsx |
npm run build prints each route with a symbol: ○ Static, ● SSG with params, ƒ Dynamic. Use it to confirm which strategy each page got.Caching & revalidation Advanced
Next.js caches work at several layers. Learn these layers and you'll understand most "why is my data stale?" bugs.
cacheComponents: true in next.config.ts). Then you mark a component or function with "use cache" to cache it, and control its lifetime with cacheLife() and cacheTag(). Read the official caching docs for the version you're using, because the defaults have changed between major releases.Streaming & Suspense Advanced
Without streaming, the slowest query blocks the whole page. With <Suspense>, the page shell appears at once and the slow parts stream in as they finish.
Advanced routing patterns Advanced
Route groups (name)
Organize routes without changing the URL. app/(marketing)/about → /about. Each group can have its own layout.
Private folders _name
app/_components is ignored by the router, so it's a safe place for helper files.
Parallel routes @slot
Render several pages in one layout at the same time. Useful for dashboards: @analytics + @team.
Intercepting routes (.)photo
Open /photo/1 in a modal while browsing the feed. A refresh shows the full page.
- app/
- (marketing)/ ← group: public site layout
- layout.tsx
- pricing/page.tsx → /pricing
- (app)/ ← group: logged-in layout
- dashboard/
- layout.tsx ← receives {children, analytics, team}
- @analytics/page.tsx
- @team/page.tsx
- dashboard/
- feed/
- (.)photo/[id]/page.tsx ← modal version
- photo/[id]/page.tsx ← full-page version
- (marketing)/ ← group: public site layout
Performance & SEO Advanced
LCP
Largest Contentful Paint. Should be under 2.5s. Use priority on the hero image.
INP
Interaction to Next Paint. Keep JS small and move logic to the server.
CLS
Cumulative Layout Shift. next/image and next/font prevent it.
Performance checklist
- Keep
"use client"as low in the tree as possible - Fetch in parallel and stream slow parts with Suspense
- Use
next/image,next/fontandnext/script(strategy="lazyOnload") - Lazy-load heavy libraries with
next/dynamic - Cache data that doesn't change often
- Check bundle size with
@next/bundle-analyzer
Environment variables & deployment Advanced
NEXT_PUBLIC_ variables. They are copied into the JavaScript that is sent to every visitor.| Option | How | Notes |
|---|---|---|
| Vercel | Import the GitHub repo | Zero config. Made by the creators of Next.js. |
| Docker | output: "standalone" in next.config | Small image. Run it anywhere. |
| VPS | npm run build && npm start + PM2 + Nginx | Full control |
| Static export | output: "export" | No server features (no SSR, actions or API routes) |
Interview questions
app/) is the modern router. It is built on React Server Components and supports nested layouts, streaming and Server Actions. The Pages Router (pages/) is the older one, with getServerSideProps and getStaticProps. New projects should use the App Router.Date.now(), Math.random(), reading window during render, and invalid HTML nesting such as a <div> inside a <p>.onClick, onChange), state or effects (useState, useEffect), browser-only APIs, or a library that depends on them. Use a Server Component for everything else.<Link> navigates on the client without a full page reload, prefetches routes when they come into view, and keeps shared layouts mounted.Practice projects
- Portfolio siteStatic pages, a Bootstrap navbar,
next/imageand metadata. - BlogDynamic routes
[slug],generateStaticParams, a loading UI and a 404 page. - Todo appServer Actions,
useActionStateandrevalidatePath, with PostgreSQL behind it (see the Backend page). - DashboardRoute groups, parallel routes, Suspense streaming and auth-protected pages.
Cheat sheet
Files
page.tsxroute UIlayout.tsxshared wrapperloading.tsxsuspense fallbackerror.tsxerror boundarynot-found.tsx404route.tsAPI endpoint
Folders
[id]dynamic[...all]catch-all[[...all]]optional catch-all(group)no URL segment_privatenot a route@slotparallel route
Navigation
<Link href>linksuseRouter()client push/backusePathname()current pathredirect()server redirectnotFound()trigger 404
Caching
revalidate = 60ISRcache: "no-store"always freshnext: { tags }tag a fetchrevalidatePath()purge a pathrevalidateTag()purge a tag