gavmac00/nextjs-app-docs huggingface dataset:
Conditional Statements
middleware.ts import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
 
export function middleware(request: NextRequest) {
  if (request.nextUrl.pathname.startsWith('/about')) {
    return NextResponse.rewrite(new URL('/about-2', request.url))
  }
 
  if (request.nextUrl.pathname.startsWith('/dashboard')) {
    return NextResponse.rewrite(new URL('/dashboard/user', request.url))
  }
}
NextResponse
The NextResponse API allows you to:
redirect the incoming request to a different URL
rewrite the response by displaying a given URL
Set request headers for API Routes, getServerSideProps, and rewrite destinations
Set response cookies
Set response headers
To produce a response from Middleware, you can:
rewrite to a route (Page or Route Handler) that produces a response
rewrite to a route (Page or Route Handler) that produces a response
return a NextResponse directly. See Producing a Response
Using Cookies
Cookies are regular headers. On a Request, they are stored in the Cookie header. On a Response they are in the Set-Cookie header. Next.js provides a convenient way to access and manipulate these cookies through the cookies extension on NextRequest and NextResponse.
For incoming requests, cookies comes with the following methods: get, getAll, set, and delete cookies. You can check for the existence of a cookie with has or remove all cookies with clear.
For outgoing responses, cookies have the following methods get, getAll, set, and delete.
middleware.ts import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
 
export function middleware(request: NextRequest) {
  // Assume a "Cookie:nextjs=fast" header to be present on the incoming request
// Getting cookies from the request using the `RequestCookies` API
  let cookie = request.cookies.get('nextjs')
  console.log(cookie) // => { name: 'nextjs', value: 'fast', Path: '/' }
  const allCookies = request.cookies.getAll()
  console.log(allCookies) // => [{ name: 'nextjs', value: 'fast' }]
 
  request.cookies.has('nextjs') // => true
  request.cookies.delete('nextjs')
  request.cookies.has('nextjs') // => false
 
  // Setting cookies on the response using the `ResponseCookies` API
  const response = NextResponse.next()
  response.cookies.set('vercel', 'fast')
  response.cookies.set({
    name: 'vercel',
    value: 'fast',
    path: '/',
  })
  cookie = response.cookies.get('vercel')
path: '/',
  })
  cookie = response.cookies.get('vercel')
  console.log(cookie) // => { name: 'vercel', value: 'fast', Path: '/' }
  // The outgoing response will have a `Set-Cookie:vercel=fast;path=/test` header.
 
  return response
}
Setting Headers
You can set request and response headers using the NextResponse API (setting request headers is available since Next.js v13.0.0).
middleware.ts import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
 
export function middleware(request: NextRequest) {
  // Clone the request headers and set a new header `x-hello-from-middleware1`
  const requestHeaders = new Headers(request.headers)
  requestHeaders.set('x-hello-from-middleware1', 'hello')
requestHeaders.set('x-hello-from-middleware1', 'hello')
 
  // You can also set request headers in NextResponse.rewrite
  const response = NextResponse.next({
    request: {
      // New request headers
      headers: requestHeaders,
    },
  })
 
  // Set a new response header `x-hello-from-middleware2`
  response.headers.set('x-hello-from-middleware2', 'hello')
  return response
}
Good to know: Avoid setting large headers as it might cause 431 Request Header Fields Too Large error depending on your backend web server configuration.
Producing a Response
You can respond from Middleware directly by returning a Response or NextResponse instance. (This is available since Next.js v13.1.0)
middleware.ts import { NextRequest, NextResponse } from 'next/server'
import { isAuthenticated } from '@lib/auth'
import { isAuthenticated } from '@lib/auth'
 
// Limit the middleware to paths starting with `/api/`
export const config = {
  matcher: '/api/:function*',
}
 
export function middleware(request: NextRequest) {
  // Call our authentication function to check the request
  if (!isAuthenticated(request)) {
    // Respond with JSON indicating an error message
    return new NextResponse(
      JSON.stringify({ success: false, message: 'authentication failed' }),
      { status: 401, headers: { 'content-type': 'application/json' } }
    )
  }
}
Advanced Middleware Flags
In v13.1 of Next.js two additional flags were introduced for middleware, skipMiddlewareUrlNormalize and skipTrailingSlashRedirect to handle advanced use cases.
skipTrailingSlashRedirect allows disabling Next.js default redirects for adding or removing trailing slashes allowing custom handling inside middleware which can allow maintaining the trailing slash for some paths but not others allowing easier incremental migrations.
next.config.js module.exports = {
  skipTrailingSlashRedirect: true,
}
middleware.js const legacyPrefixes = ['/docs', '/blog']
 
export default async function middleware(req) {
  const { pathname } = req.nextUrl
 
  if (legacyPrefixes.some((prefix) => pathname.startsWith(prefix))) {
    return NextResponse.next()
  }
 
  // apply trailing slash handling
  if (
    !pathname.endsWith('/') &&
    !pathname.match(/((?!\.well-known(?:\/.*)?)(?:[^/]+\/)*[^/]+\.\w+)/)
  ) {
    req.nextUrl.pathname += '/'
    return NextResponse.redirect(req.nextUrl)
  }
return NextResponse.redirect(req.nextUrl)
  }
}
skipMiddlewareUrlNormalize allows disabling the URL normalizing Next.js does to make handling direct visits and client-transitions the same. There are some advanced cases where you need full control using the original URL which this unlocks.
next.config.js module.exports = {
  skipMiddlewareUrlNormalize: true,
}
middleware.js export default async function middleware(req) {
  const { pathname } = req.nextUrl
 
  // GET /_next/data/build-id/hello.json
 
  console.log(pathname)
  // with the flag this now /_next/data/build-id/hello.json
  // without the flag this would be normalized to /hello
}
Version History
// without the flag this would be normalized to /hello
}
Version History
VersionChangesv13.1.0Advanced Middleware flags addedv13.0.0Middleware can modify request headers, response headers, and send responsesv12.2.0Middleware is stable, please see the upgrade guidev12.0.9Enforce absolute URLs in Edge Runtime (PR)v12.0.0Middleware (Beta) added
Intercepting RoutesIntercepting routes allows you to load a route within the current layout while keeping the context for the current page. This routing paradigm can be useful when you want to "intercept" a certain route to show a different route.
For example, when clicking on a photo from within a feed, a modal overlaying the feed should show up with the photo. In this case, Next.js intercepts the /feed route and "masks" this URL to show /photo/123 instead.
However, when navigating to the photo directly by for example when clicking a shareable URL or by refreshing the page, the entire photo page should render instead of the modal. No route interception should occur.
Convention
Intercepting routes can be defined with the (..) convention, which is similar to relative path convention ../ but for segments.
You can use:
(.) to match segments on the same level
(..) to match segments one level above
(.) to match segments on the same level
(..) to match segments one level above
(..)(..) to match segments two levels above
(...) to match segments from the root app directory
For example, you can intercept the photo segment from within the feed segment by creating a (..)photo directory.
Note that the (..) convention is based on route segments, not the file-system.
Examples
Modals
Intercepting Routes can be used together with Parallel Routes to create modals.
Using this pattern to create modals overcomes some common challenges when working with modals, by allowing you to:
Make the modal content shareable through a URL
Preserve context when the page is refreshed, instead of closing the modal
Close the modal on backwards navigation rather than going to the previous route
Reopen the modal on forwards navigation
Reopen the modal on forwards navigation
In the above example, the path to the photo segment can use the (..) matcher since @modal is a slot and not a segment. This means that the photo route is only one segment level higher, despite being two file-system levels higher.
Other examples could include opening a login modal in a top navbar while also having a dedicated /login page, or opening a shopping cart in a side modal.
View an example of modals with Intercepted and Parallel Routes.
Dynamic RoutesWhen you don't know the exact segment names ahead of time and want to create routes from dynamic data, you can use Dynamic Segments that are filled in at request time or prerendered at build time.
Convention
A Dynamic Segment can be created by wrapping a folder's name in square brackets: [folderName]. For example, [id] or [slug].
Dynamic Segments are passed as the params prop to layout, page, route, and generateMetadata functions.
Example
For example, a blog could include the following route app/blog/[slug]/page.js where [slug] is the Dynamic Segment for blog posts.
app/blog/[slug]/page.tsx export default function Page({ params }: { params: { slug: string } }) {
  return <div>My Post: {params.slug}</div>
}
return <div>My Post: {params.slug}</div>
}
RouteExample URLparamsapp/blog/[slug]/page.js/blog/a{ slug: 'a' }app/blog/[slug]/page.js/blog/b{ slug: 'b' }app/blog/[slug]/page.js/blog/c{ slug: 'c' }
See the generateStaticParams() page to learn how to generate the params for the segment.
Good to know: Dynamic Segments are equivalent to Dynamic Routes in the pages directory.
Generating Static Params
The generateStaticParams function can be used in combination with dynamic route segments to statically generate routes at build time instead of on-demand at request time.
app/blog/[slug]/page.tsx export async function generateStaticParams() {
  const posts = await fetch('https://.../posts').then((res) => res.json())
 
  return posts.map((post) => ({
    slug: post.slug,
return posts.map((post) => ({
    slug: post.slug,
  }))
}
The primary benefit of the generateStaticParams function is its smart retrieval of data. If content is fetched within the generateStaticParams function using a fetch request, the requests are automatically deduplicated. This means a fetch request with the same arguments across multiple generateStaticParams, Layouts, and Pages will only be made once, which decreases build times.
Use the migration guide if you are migrating from the pages directory.
See generateStaticParams server function documentation for more information and advanced use cases.
Catch-all Segments
Dynamic Segments can be extended to catch-all subsequent segments by adding an ellipsis inside the brackets [...folderName].
For example, app/shop/[...slug]/page.js will match /shop/clothes, but also /shop/clothes/tops, /shop/clothes/tops/t-shirts, and so on.
RouteExample URLparamsapp/shop/[...slug]/page.js/shop/a{ slug: ['a'] }app/shop/[...slug]/page.js/shop/a/b{ slug: ['a', 'b'] }app/shop/[...slug]/page.js/shop/a/b/c{ slug: ['a', 'b', 'c'] }
Optional Catch-all Segments
Catch-all Segments can be made optional by including the parameter in double square brackets: [[...folderName]].
For example, app/shop/[[...slug]]/page.js will also match /shop, in addition to /shop/clothes, /shop/clothes/tops, /shop/clothes/tops/t-shirts.
The difference between catch-all and optional catch-all segments is that with optional, the route without the parameter is also matched (/shop in the example above).
RouteExample URLparamsapp/shop/[[...slug]]/page.js/shop{}app/shop/[[...slug]]/page.js/shop/a{ slug: ['a'] }app/shop/[[...slug]]/page.js/shop/a/b{ slug: ['a', 'b'] }app/shop/[[...slug]]/page.js/shop/a/b/c{ slug: ['a', 'b', 'c'] }
TypeScript
When using TypeScript, you can add types for params depending on your configured route segment.
app/blog/[slug]/page.tsx export default function Page({ params }: { params: { slug: string } }) {
  return <h1>My Page</h1>
}
Routeparams Type Definitionapp/blog/[slug]/page.js{ slug: string }app/shop/[...slug]/page.js{ slug: string[] }app/[categoryId]/[itemId]/page.js{ categoryId: string, itemId: string }
Good to know: This may be done automatically by the TypeScript plugin in the future.
Parallel RoutesParallel Routing allows you to simultaneously or conditionally render one or more pages in the same layout. For highly dynamic sections of an app, such as dashboards and feeds on social sites, Parallel Routing can be used to implement complex routing patterns.
For example, you can simultaneously render the team and analytics pages.
Parallel Routing allows you to define independent error and loading states for each route as they're being streamed in independently.
Parallel Routing also allows you to conditionally render a slot based on certain conditions, such as authentication state. This enables fully separated code on the same URL.
Convention
Parallel routes are created using named slots. Slots are defined with the @folder convention, and are passed to the same-level layout as props.
Slots are not route segments and do not affect the URL structure. The file path /@team/members would be accessible at /members.
For example, the following file structure defines two explicit slots: @analytics and @team.
For example, the following file structure defines two explicit slots: @analytics and @team.
The folder structure above means that the component in app/layout.js now accepts the @analytics and @team slots props, and can render them in parallel alongside the children prop:
app/layout.tsx export default function Layout(props: {
  children: React.ReactNode
  analytics: React.ReactNode
  team: React.ReactNode
}) {
  return (
    <>
      {props.children}
      {props.team}
      {props.analytics}
    </>
  )
}
Good to know: The children prop is an implicit slot that does not need to be mapped to a folder. This means app/page.js is equivalent to app/@children/page.js.
Unmatched Routes
By default, the content rendered within a slot will match the current URL.
Unmatched Routes
By default, the content rendered within a slot will match the current URL.
In the case of an unmatched slot, the content that Next.js renders differs based on the routing technique and folder structure.
default.js
You can define a default.js file to render as a fallback when Next.js cannot recover a slot's active state based on the current URL.
Consider the following folder structure. The @team slot has a settings directory, but @analytics does not.
If you were to navigate from the root / to /settings, the content that gets rendered is different based on the type of navigation and the availability of the default.js file.
With @analytics/default.jsWithout @analytics/default.jsSoft Navigation@team/settings/page.js and @analytics/page.js@team/settings/page.js and @analytics/page.jsHard Navigation@team/settings/page.js and @analytics/default.js404
Soft Navigation
Soft Navigation
On a soft navigation - Next.js will render the slot's previously active state, even if it doesn't match the current URL.
Hard Navigation
On a hard navigation - a navigation that requires a full page reload - Next.js will first try to render the unmatched slot's default.js file. If that's not available, a 404 gets rendered.
The 404 for unmatched routes helps ensure that you don't accidentally render a route that shouldn't be parallel rendered.
useSelectedLayoutSegment(s)
Both useSelectedLayoutSegment and useSelectedLayoutSegments accept a parallelRoutesKey, which allows you read the active route segment within that slot.
app/layout.tsx 'use client'
 
import { useSelectedLayoutSegment } from 'next/navigation'
 
export default async function Layout(props: {
  //...
  authModal: React.ReactNode
}) {
  const loginSegments = useSelectedLayoutSegment('authModal')
}) {
  const loginSegments = useSelectedLayoutSegment('authModal')
  // ...
}
When a user navigates to @authModal/login, or /login in the URL bar, loginSegments will be equal to the string "login".
Examples
Modals
Parallel Routing can be used to render modals.
The @authModal slot renders a <Modal> component that can be shown by navigating to a matching route, for example /login.
app/layout.tsx export default async function Layout(props: {
  // ...
  authModal: React.ReactNode
}) {
  return (
    <>
      {/* ... */}
      {props.authModal}
    </>
  )
}
app/@authModal/login/page.tsx import { Modal } from 'components/modal'
 
export default function Login() {
  return (
    <Modal>
      <h1>Login</h1>
return (
    <Modal>
      <h1>Login</h1>
      {/* ... */}
    </Modal>
  )
}
To ensure that the contents of the modal don't get rendered when it's not active, you can create a default.js file that returns null.
app/@authModal/default.tsx export default function Default() {
  return null
}
Dismissing a modal
If a modal was initiated through client navigation, e.g. by using <Link href="/login">, you can dismiss the modal by calling router.back() or by using a Link component.
app/@authModal/login/page.tsx 'use client'
import { useRouter } from 'next/navigation'
import { Modal } from 'components/modal'
 
export default async function Login() {
  const router = useRouter()
  return (
    <Modal>
const router = useRouter()
  return (
    <Modal>
      <span onClick={() => router.back()}>Close modal</span>
      <h1>Login</h1>
      ...
    </Modal>
  )
}
More information on modals is covered in the Intercepting Routes section.
If you want to navigate elsewhere and dismiss a modal, you can also use a catch-all route.
app/@authModal/[...catchAll]/page.tsx export default function CatchAll() {
  return null
}
Catch-all routes take precedence over default.js.
Conditional Routes
Parallel Routes can be used to implement conditional routing. For example, you can render a @dashboard or @login route depending on the authentication state.
app/layout.tsx import { getUser } from '@/lib/auth'
 
export default function Layout({
  dashboard,
  login,
}: {
  dashboard: React.ReactNode
dashboard,
  login,
}: {
  dashboard: React.ReactNode
  login: React.ReactNode
}) {
  const isLoggedIn = getUser()
  return isLoggedIn ? dashboard : login
}
Project Organization and File ColocationApart from routing folder and file conventions, Next.js is unopinionated about how you organize and colocate your project files.
This page shares default behavior and features you can use to organize your project.
Safe colocation by default
Project organization features
Project organization strategies
Safe colocation by default
In the app directory, nested folder hierarchy defines route structure.
Each folder represents a route segment that is mapped to a corresponding segment in a URL path.
However, even though route structure is defined through folders, a route is not publicly accessible until a page.js or route.js file is added to a route segment.
And, even when a route is made publicly accessible, only the content returned by page.js or route.js is sent to the client.
This means that project files can be safely colocated inside route segments in the app directory without accidentally being routable.
Good to know:
Good to know:
This is different from the pages directory, where any file in pages is considered a route.
While you can colocate your project files in app you don't have to. If you prefer, you can keep them outside the app directory.
Project organization features
Next.js provides several features to help you organize your project.
Private Folders
Private folders can be created by prefixing a folder with an underscore: _folderName
This indicates the folder is a private implementation detail and should not be considered by the routing system, thereby opting the folder and all its subfolders out of routing.
Since files in the app directory can be safely colocated by default, private folders are not required for colocation. However, they can be useful for:
Separating UI logic from routing logic.
Consistently organizing internal files across a project and the Next.js ecosystem.
Sorting and grouping files in code editors.
Sorting and grouping files in code editors.
Avoiding potential naming conflicts with future Next.js file conventions.
Good to know
While not a framework convention, you might also consider marking files outside private folders as "private" using the same underscore pattern.
You can create URL segments that start with an underscore by prefixing the folder name with %5F (the URL-encoded form of an underscore): %5FfolderName.
If you don't use private folders, it would be helpful to know Next.js special file conventions to prevent unexpected naming conflicts.
Route Groups
Route groups can be created by wrapping a folder in parenthesis: (folderName)
This indicates the folder is for organizational purposes and should not be included in the route's URL path.
Route groups are useful for:
Organizing routes into groups e.g. by site section, intent, or team.
Enabling nested layouts in the same route segment level:
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
src Directory
Next.js supports storing application code (including app) inside an optional src directory. This separates application code from project configuration files which mostly live in the root of a project.
Module Path Aliases
Next.js supports Module Path Aliases which make it easier to read and maintain imports across deeply nested project files.
app/dashboard/settings/analytics/page.js // before
import { Button } from '../../../components/button'
 
// after
import { Button } from '@/components/button'
Project organization strategies
There is no "right" or "wrong" way when it comes to organizing your own files and folders in a Next.js project.
The following section lists a very high-level overview of common strategies. The simplest takeaway is to choose a strategy that works for you and your team and be consistent across the project.
Good to know: In our examples below, we're using components and lib folders as generalized placeholders, their naming has no special framework significance and your projects might use other folders like ui, utils, hooks, styles, etc.
Store project files outside of app
This strategy stores all application code in shared folders in the root of your project and keeps the app directory purely for routing purposes.
Store project files in top-level folders inside of app
This strategy stores all application code in shared folders in the root of the app directory.
Split project files by feature or route
This strategy stores globally shared application code in the root app directory and splits more specific application code into the route segments that use them.
Route GroupsIn the app directory, nested folders are normally mapped to URL paths. However, you can mark a folder as a Route Group to prevent the folder from being included in the route's URL path.
This allows you to organize your route segments and project files into logical groups without affecting the URL path structure.
Route groups are useful for:
Organizing routes into groups e.g. by site section, intent, or team.
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
Convention
A route group can be created by wrapping a folder's name in parenthesis: (folderName)
Examples
Organize routes without affecting the URL path
To organize routes without affecting the URL, create a group to keep related routes together. The folders in parenthesis will be omitted from the URL (e.g. (marketing) or (shop)).