Skip to content

Reading Next.js Docs

Summary after reading Next.js docs.

Next.js is a React framework for building full-stack web applications. You use React Components to build user interfaces, and Next.js for additional features and optimizations.

How to use the docs

The docs are organized into 4 sections:

  • Getting Started: Step-by-step tutorials to help you create a new application and learn the core Next.js features.
  • Guides: Tutorials on specific use cases, choose what's relevant to you.
  • Deep Dive: In-depth explanations on how Next.js works.
  • API Reference: Detailed technical reference for every feature.

Next.js has 2 sets of routers. The newer App Router that supports Server Components. The original pages router is still supported and being improved.

App Router

The App Router is a file-system based router that uses React's latest features such as Server Components, Suspense, and Server Functions.

Installation

npx create-next-app@latest # command to create a next.js project

The above command will prompt you to ask couple of questions.

There is a method to do manual installation.

npm install next@latest react@latest react-dom@latest
{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  }
}

To run dev server :

$ npm run dev

Top Level Files

  • next.config.js - Configuration file for Next.js

  • package.json - Project dependencies and scripts

  • instrumentation.ts - OpenTelemetry and Instrumentation file
  • middleware.ts - Next.js request middleware
  • .env - Environment variables
  • .env.local - Local environment variables
  • .env.production - Production environment variables
  • .env.development - Development environment variables
  • .eslintrc.json - Configuration file for ESLint
  • .gitignore - Git files and folders to ignore
  • next-env.d.ts - TypeScript declaration file for Next.js
  • tsconfig.json - Configuration file for TypeScript
  • jsconfig.json - Configuration file for JavaScript

Routing Files

layout  .js .jsx .tsx   Layout
page    .js .jsx .tsx   Page
loading .js .jsx .tsx   Loading UI
not-found   .js .jsx .tsx   Not found UI
error   .js .jsx .tsx   Error UI
global-error    .js .jsx .tsx   Global error UI
route   .js .ts API endpoint
template    .js .jsx .tsx   Re-rendered layout
default .js .jsx .tsx   Parallel route fallback page

Nested Routes

Nested routes
folder  Route segment
folder/folder   Nested route segment

Dynamic routes

[folder]    Dynamic route segment
[...folder] Catch-all route segment
[[...folder]]   Optional catch-all route segment

Route Groups and private folders

(folder)    Group routes without affecting routing
_folder Opt folder and all child segments out of routing

Parallel and Intercepted Routes

@folder Named slot
(.)folder   Intercept same level
(..)folder  Intercept one level above
(..)(..)folder  Intercept two levels above
(...)folder Intercept from root

Private Folders

Private folders can be created by prefixing it with an underscore.

Route Groups

Route groups are useful for:

  • Organizing routes by site section, intent, or team. e.g. marketing pages, admin pages, etc.
  • Enabling nested layouts in the same route segment level:
    • Creating multiple nested layouts in the same segment, including multiple root layouts
    • Adding a layout to a subset of routes in a common segment

Mutli-Layout Setup

To have multiple layouts.

Creating Layouts and Pages

Next.js uses file-system based routing, meaning you can use folders and files to define routes. This page will guide you through how to create layouts and pages, and link between them.

Creating a Page

A page is UI that is rendered on a specific route. To create a page, add a page file inside the app directory and default export a React component.

export default function Page() {
  return <h1>Hello Next.js!</h1>
}

Creating a layout

A layout is UI that is shared between multiple pages. On navigation, layouts preserve state, remain interactive, and do not rerender.

RootLayout
export default function DashboardLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body>
        {/* Layout UI */}
        {/* Place children where you want to render a page or nested layout */}
        <main>{children}</main>
      </body>
    </html>
  )
}

The layout above is called a root layout because it's defined at the root of the app directory. The root layout is required and must contain html and body tags.

Linking between pages

You can use the <Link> component to navigate between routes. <Link> is a built-in Next.js component that extends the HTML <a> tag to provide prefetching and client-side navigation.

Images

The Next.js <Image> component extends the HTML <img> element to provide:

  • Size optimization: Automatically serving correctly sized images for each device, using modern image formats like WebP.
  • Visual stability: Preventing layout shift automatically when images are loading.
  • Faster page loads: Only loading images when they enter the viewport using native browser lazy loading, with optional blur-up placeholders.
  • Asset flexibility: Resizing images on-demand, even images stored on remote servers.
import Image from 'next/image'

export default function Page() {
  return <Image src="" alt="" />
}

Note : The image tag should use the height and width attributes to avoid layout shifts.

Remote Images

To safely allow images from remote servers, you need to define a list of supported URL patterns in next.config.js. Be as specific as possible to prevent malicious usage. For example, the following configuration will only allow images from a specific AWS S3 bucket:

import type { NextConfig } from 'next'

const config: NextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 's3.amazonaws.com',
        port: '',
        pathname: '/my-bucket/**',
        search: '',
      },
    ],
  },
}

export default config

Fonts

The next/font module automatically optimizes your fonts and removes external network requests for improved privacy and performance.

Google fonts

You can automatically self-host any Google Font. Fonts are included stored as static assets and served from the same domain as your deployment, meaning no requests are sent to Google by the browser when the user visits your site.

import { Geist } from 'next/font/google'

const geist = Geist({
  subsets: ['latin'],
})

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en" className={geist.className}>
      <body>{children}</body>
    </html>
  )
}

CSS Usage

CSS MODULES : CSS Modules locally scope CSS by generating unique class names. This allows you to use the same class in different files without worrying about naming collisions.

To start using CSS Modules, create a new file with the extension .module.css and import it into any component inside the app directory:

.blog {
  padding: 24px;
}
import styles from './blog.module.css'

export default function Page() {
  return <main className={styles.blog}></main>
}

Global CSS

You can use global CSS to apply styles across your application.

Create a app/global.css file and import it in the root layout to apply the styles to every route in your application:

body {
  padding: 20px 20px 60px;
  max-width: 680px;
  margin: 0 auto;
}

How to use Server and Client Components

By default, layouts and pages are Server Components, which lets you fetch data and render parts of your UI on the server, optionally cache the result, and stream it to the client. When you need interactivity or browser APIs, you can use Client Components to layer in functionality.

When to use Server and Client Components?

The client and server environments have different capabilities. Server and Client components allow you to run logic in each environment depending on your use case.

Use Client Components when you need:

  • State and event handlers. E.g. onClick, onChange.
  • Lifecycle logic. E.g. useEffect.
  • Browser-only APIs. E.g. localStorage, window, Navigator.geolocation, etc.
  • Custom hooks.

Use Server Components when you need:

  • Fetch data from databases or APIs close to the source.
  • Use API keys, tokens, and other secrets without exposing them to the client.
  • Reduce the amount of JavaScript sent to the browser.
  • Improve the First Contentful Paint (FCP), and stream content progressively to the client.

Using Client Components

You can create a Client Component by adding the "use client" directive at the top of the file, above your imports.

'use client'

import { useState } from 'react'

export default function Counter() {
  const [count, setCount] = useState(0)

  return (
    <div>
      <p>{count} likes</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  )
}

Passing data from Server to Client Components

You can pass data from Server Components to Client Components using props

import LikeButton from '@/app/ui/like-button'
import { getPost } from '@/lib/data'

export default async function Page({ params }: { params: { id: string } }) {
  const post = await getPost(params.id)

  return <LikeButton likes={post.likes} />
}
'use client'

export default function LikeButton({ likes }: { likes: number }) {
  // ...
}

Preventing Server side code from rendering on client.

npm install server-only
import 'server-only'

export async function getData() {
  const res = await fetch('https://external-service.com/data', {
    headers: {
      authorization: process.env.API_KEY,
    },
  })

  return res.json()
}

Fetching data

Server Components

You can fetch data in Server Components using:

  • The fetch API
  • An ORM or database

To fetch data with the fetch API, turn your component into an asynchronous function, and await the fetch call. For example:

export default async function Page() {
  const data = await fetch('https://api.vercel.app/blog')
  const posts = await data.json()
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  )
}

To avoid caching use { cache: 'no-store' }

Client Components

There are two ways to fetch data in Client Components, using:

  • React's use hook
  • A community library like SWR or React Query

HOW TO CACHE AND REVALIDATE DATA

Caching is a technique for storing the result of data fetching and other computations so that future requests for the same data can be served faster, without doing the work again. While revalidation allows you to update cache entries without having to rebuild your entire application.

By default, fetch requests are not cached. You can cache individual requests by setting the cache option to 'force-cache'.

How to update data

You can update data in Next.js using React's Server Functions.

Server Functions

A Server Function is an asynchronous function that is executed on the server. Server Functions are inherently asynchronous because they are invoked by the client using a network request. When invoked as part of an action, they are also called Server Actions.

Deploying

How to deploy your Next.js application

Next.js can be deployed as a Node.js server, Docker container, static export, or adapted to run on different platforms.

Deployment Option Feature Support
Node.js server All
Docker container All
Static export Limited
Adapters Platform-specific

Node.js server

Next.js can be deployed to any provider that supports Node.js. Ensure your package.json has the "build" and "start" scripts:

{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start"
  }
}