NextJS keypoints
About 1381 wordsAbout 5 min
ReactNextJS
2025-03-15
Layout and Tempaltes
layout.tsx
A layout is UI that is shared between multiple pages. On navigation, layouts preserve state, remain interactive, and do not rerender.
You can define a layout by default exporting a React component from a layout file. The component should accept a children prop which can be a page or another layout.
Link and Navigate
The App Router uses a hybrid approach for routing and navigation. On the server, your application code is automatically code-split by route segments. And on the client, Next.js prefetches and caches the route segments. This means, when a user navigates to a new route, the browser doesn't reload the page, and only the route segments that change re-render - improving the navigation experience and performance.
Link
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.
It is the primary and recommended way to navigate between routes in Next.js.
useRouter()
The useRouter hook allows you to programmatically change routes from Client Components.
Use the <Link>
component to navigate between routes unless you have a specific requirement for using useRouter.
redirect
For Server Components, use the redirect function instead.
Using the native History API
Next.js allows you to use the native window.history.pushState and window.history.replaceState methods to update the browser's history stack without reloading the page.
- window.history.pushState
Use it to add a new entry to the browser's history stack. The user can navigate back to the previous state.
- window.history.replaceState
Use it to replace the current entry on the browser's history stack. The user is not able to navigate back to the previous state.
Error Handling
Errors can be divided into two categories: expected errors and uncaught exceptions.
- Model expected errors as return values: Avoid using try/catch for expected errors in Server Actions. Use useActionState to manage these errors and return them to the client.
- Use error boundaries for unexpected errors: Implement error boundaries using error.tsx and global-error.tsx files to handle unexpected errors and provide a fallback UI.
Uncaught exceptions are unexpected errors that indicate bugs or issues that should not occur during the normal flow of your application. These should be handled by throwing errors, which will then be caught by error boundaries.
- Common: Handle uncaught errors below the root layout with error.js.
- Optional: Handle granular uncaught errors with nested error.js files (e.g. app/dashboard/error.js)
- Uncommon: Handle uncaught errors in the root layout with global-error.js.
Create an error boundary by adding an error.tsx file inside a route segment and exporting a React component.
If you want errors to bubble up to the parent error boundary, you can throw when rendering the error component.
While less common, you can handle errors in the root layout using app/global-error.js, located in the root app directory, even when leveraging internationalization. Global error UI must define its own <html>
and <body>
tags, since it is replacing the root layout or template when active.
Loading UI and Streaming
Instant Loading States
The special file loading.js helps you create meaningful Loading UI with React Suspense. With this convention, you can show an instant loading state from the server while the content of a route segment loads. The new content is automatically swapped in once rendering is complete.
In the same folder, loading.js will be nested inside layout.js. It will automatically wrap the page.js file and any children below in a <Suspense>
boundary.
Streaming with Suspense
In addition to loading.js, you can also manually create Suspense Boundaries for your own UI components.
Some browsers buffer a streaming response. You may not see the streamed response until the response exceeds 1024 bytes.
What is Streaming?
With SSR, there's a series of steps that need to be completed before a user can see and interact with a page:
- First, all data for a given page is fetched on the server.
- The server then renders the HTML for the page.
- The HTML, CSS, and JavaScript for the page are sent to the client.
- A non-interactive user interface is shown using the generated HTML, and CSS.
- Finally, React hydrates the user interface to make it interactive.
These steps are sequential and blocking, meaning the server can only render the HTML for a page once all the data has been fetched. And, on the client, React can only hydrate the UI once the code for all components in the page has been downloaded.
Streaming allows you to break down the page's HTML into smaller chunks and progressively send those chunks from the server to the client.
Streaming works well with React's component model because each component can be considered a chunk. Components that have higher priority (e.g. product information) or that don't rely on data can be sent first (e.g. layout), and React can start hydration earlier. Components that have lower priority (e.g. reviews, related products) can be sent in the same server request after their data has been fetched.
Page Router vs App Router
In Next.js, the App Router and Pages Router are two different routing systems, each with its own approach to handling routes, data fetching, and rendering.
Pages Router (Old System - pages/ Directory)
The Pages Router is the traditional Next.js routing system, where each file inside the pages/ directory automatically becomes a route. Like the following
Features of Pages Router
- Uses pages/ directory for routing.
- Supports getServerSideProps, getStaticProps, getInitialProps for data fetching.
- Uses client-side rendering (CSR), server-side rendering (SSR), and static site generation (SSG).
- Relies on next/link for navigation.
- Each page is a React component that gets rendered on the client or server.
- A file inside /pages becomes a route automatically (/index.tsx → /)
Note
getStaticProps (SSG - Static Site Generation) getServerSideProps (SSR - Server-Side Rendering) getInitialProps (Deprecated in Pages Router, Still Used in _app.js)
❌ Limitations
- No built-in React Server Components.
- Limited flexibility for rendering approaches.
- Complex API for managing layouts and fetching data.
App Router (New System - app/ Directory)
The App Router was introduced in Next.js 13 and is based on React Server Components (RSC). It uses the /app directory instead of /pages.
Key Features
- Uses app/ directory for routing.
- Based on React Server Components (RSC).
- Supports Layouts, Server Components, and Streaming.
- Uses async/await for data fetching in components.
- API routes are replaced by server actions.
- Uses loading.tsx, error.tsx, and layout.tsx for better control over loading and errors.
Which One to Use?
- Use Pages Router (/pages) if you need traditional getServerSideProps, getStaticProps, or prefer a simple structure.
- Use App Router (/app) if you want React Server Components, improved performance, streaming, and layouts.
The App Router (/app) is the future of Next.js.
Pages Router (/pages) is still supported but will eventually be phased out.
Turbopack
Turbopack is an incremental bundler optimized for JavaScript and TypeScript, written in Rust, and built into Next.js. You can use Turbopack with both the Pages and App Router for a much faster local development experience.
Edge Runtime
Edge Runtime in Next.js is a lightweight, optimized JavaScript runtime that runs at the edge, close to the user. It allows faster request processing by reducing latency compared to traditional server-based execution.
Instead of running on a full Node.js environment, Edge Runtime is based on Web APIs (similar to Cloudflare Workers, Deno, and Vercel Edge Functions). It is designed for low-latency, high-performance server-side execution.
In the context of Next.js, "Edge" refers to running server-side logic at the edge locations instead of traditional backend servers. This is achieved through Edge Runtimes (e.g., Vercel Edge Functions, Cloudflare Workers), which are optimized for low-latency execution.
Server Components
Server Components cannot use state (useState, useEffect), event listeners, or hooks. To handle interactivity, wrap client-side logic in a Client Component.
You can access cookies or headers directly in Server Components.
When to Use Server Components?
- ✅ Fetching data from databases or APIs
- ✅ Rendering content-heavy pages without extra JS
- ✅ Improving SEO (pre-rendering content)
- ✅ Accessing cookies, sessions, or headers
When to Use Client Components?
- ✅ Interactivity (buttons, forms, animations)
- ✅ Using hooks (useState, useEffect)
- ✅ Handling user input and event listeners