gavmac00/nextjs-app-docs huggingface dataset:
Even though routes inside (marketing) and (shop) share the same URL hierarchy, you can create a different layout for each group by adding a layout.js file inside their folders.
Opting specific segments into a layout
To opt specific routes into a layout, create a new route group (e.g. (shop)) and move the routes that share the same layout into the group (e.g. account and cart). The routes outside of the group will not share the layout (e.g. checkout).
Creating multiple root layouts
To create multiple root layouts, remove the top-level layout.js file, and add a layout.js file inside each route groups. This is useful for partitioning an application into sections that have a completely different UI or experience. The <html> and <body> tags need to be added to each root layout.
In the example above, both (marketing) and (shop) have their own root layout.
Good to know:
Good to know:
The naming of route groups has no special significance other than for organization. They do not affect the URL path.
Routes that include a route group should not resolve to the same URL path as other routes. For example, since route groups don't affect URL structure, (marketing)/about/page.js and (shop)/about/page.js would both resolve to /about and cause an error.
If you use multiple root layouts without a top-level layout.js file, your home page.js file should be defined in one of the route groups, For example: app/(marketing)/page.js.
Navigating across multiple root layouts will cause a full page load (as opposed to a client-side navigation). For example, navigating from /cart that uses app/(shop)/layout.js to /blog that uses app/(marketing)/layout.js will cause a full page load. This only applies to multiple root layouts.
Static and Dynamic RenderingIn Next.js, a route can be statically or dynamically rendered.
In a static route, components are rendered on the server at build time. The result of the work is cached and reused on subsequent requests.
In a dynamic route, components are rendered on the server at request time.
Static Rendering (Default)
By default, Next.js statically renders routes to improve performance. This means all the rendering work is done ahead of time and can be served from a Content Delivery Network (CDN) geographically closer to the user.
Static Data Fetching (Default)
By default, Next.js will cache the result of fetch() requests that do not specifically opt out of caching behavior. This means that fetch requests that do not set a cache option will use the force-cache option.
If any fetch requests in the route use the revalidate option, the route will be re-rendered statically during revalidation.
To learn more about caching data fetching requests, see the Caching and Revalidating page.
Dynamic Rendering
During static rendering, if a dynamic function or a dynamic fetch() request (no caching) is discovered, Next.js will switch to dynamically rendering the whole route at request time. Any cached data requests can still be re-used during dynamic rendering.
This table summarizes how dynamic functions and caching affect the rendering behavior of a route:
Data FetchingDynamic FunctionsRenderingStatic (Cached)NoStaticStatic (Cached)YesDynamicNot CachedNoDynamicNot CachedYesDynamic
Note how dynamic functions always opt the route into dynamic rendering, regardless of whether the data fetching is cached or not. In other words, static rendering is dependent not only on the data fetching behavior, but also on the dynamic functions used in the route.
Good to know: In the future, Next.js will introduce hybrid server-side rendering where layouts and pages in a route can be independently statically or dynamically rendered, instead of the whole route.
Dynamic Functions
Dynamic functions rely on information that can only be known at request time such as a user's cookies, current requests headers, or the URL's search params. In Next.js, these dynamic functions are:
Using cookies() or headers() in a Server Component will opt the whole route into dynamic rendering at request time.
Using useSearchParams() in Client Components will skip static rendering and instead render all Client Components up to the nearest parent Suspense boundary on the client.
We recommend wrapping the Client Component that uses useSearchParams() in a <Suspense/> boundary. This will allow any Client Components above it to be statically rendered. Example.
Using the searchParams Pages prop will opt the page into dynamic rendering at request time.
Dynamic Data Fetching
Dynamic Data Fetching
Dynamic data fetches are fetch() requests that specifically opt out of caching behavior by setting the cache option to 'no-store' or revalidate to 0.
The caching options for all fetch requests in a layout or page can also be set using the segment config object.
To learn more about Dynamic Data Fetching, see the Data Fetching page.
Edge and Node.js Runtimes
In the context of Next.js, "runtime" refers to the set of libraries, APIs, and general functionality available to your code during execution.
Next.js has two server runtimes where you can render parts of your application code:
Node.js Runtime
Edge Runtime
Each runtime has its own set of APIs. Please refer to the Node.js Docs and Edge Docs for the full list of available APIs. Both runtimes can also support streaming depending on your deployment infrastructure.
By default, the app directory uses the Node.js runtime. However, you can opt into different runtimes (e.g. Edge) on a per-route basis.
Runtime Differences
There are many considerations to make when choosing a runtime. This table shows the major differences at a glance. If you want a more in-depth analysis of the differences, check out the sections below.
NodeServerlessEdgeCold Boot/~250msInstantHTTP StreamingYesYesYesIOAllAllfetchScalability/HighHighestSecurityNormalHighHighLatencyNormalLowLowestnpm PackagesAllAllA smaller subset
Edge Runtime
In Next.js, the lightweight Edge Runtime is a subset of available Node.js APIs.
The Edge Runtime is ideal if you need to deliver dynamic, personalized content at low latency with small, simple functions. The Edge Runtime's speed comes from its minimal use of resources, but that can be limiting in many scenarios.
For example, code executed in the Edge Runtime on Vercel cannot exceed between 1 MB and 4 MB, this limit includes imported packages, fonts and files, and will vary depending on your deployment infrastructure.
Node.js Runtime
Using the Node.js runtime gives you access to all Node.js APIs, and all npm packages that rely on them. However, it's not as fast to start up as routes using the Edge runtime.
Deploying your Next.js application to a Node.js server will require managing, scaling, and configuring your infrastructure. Alternatively, you can consider deploying your Next.js application to a serverless platform like Vercel, which will handle this for you.
Serverless Node.js
Serverless is ideal if you need a scalable solution that can handle more complex computational loads than the Edge Runtime. With Serverless Functions on Vercel, for example, your overall code size is 50MB including imported packages, fonts, and files.
The downside compared to routes using the Edge is that it can take hundreds of milliseconds for Serverless Functions to boot up before they begin processing requests. Depending on the amount of traffic your site receives, this could be a frequent occurrence as the functions are not frequently "warm".
Examples
Segment Runtime Option
Examples
Segment Runtime Option
You can specify a runtime for individual route segments in your Next.js application. To do so, declare a variable called runtime and export it. The variable must be a string, and must have a value of either 'nodejs' or 'edge' runtime.The following example demonstrates a page route segment that exports a runtime with a value of 'edge':app/page.tsx export const runtime = 'edge' // 'nodejs' (default) | 'edge'You can also define runtime on a layout level, which will make all routes under the layout run on the edge runtime:app/layout.tsx export const runtime = 'edge' // 'nodejs' (default) | 'edge'If the segment runtime is not set, the default nodejs runtime will be used. You do not need to use the runtime option if you do not plan to change from the Node.js runtime.
Server ActionsServer Actions are an alpha feature in Next.js, built on top of React Actions. They enable server-side data mutations, reduced client-side JavaScript, and progressively enhanced forms. They can be defined inside Server Components and/or called from Client Components:
With Server Components:
app/add-to-cart.js import { cookies } from 'next/headers'
 
// Server action defined inside a Server Component
export default function AddToCart({ productId }) {
  async function addItem(data) {
    'use server'
 
    const cartId = cookies().get('cartId')?.value
    await saveToDb({ cartId, data })
  }
 
  return (
    <form action={addItem}>
      <button type="submit">Add to Cart</button>
    </form>
  )
}
With Client Components:
app/actions.js 'use server'
 
export async function addItem(data) {
app/actions.js 'use server'
 
export async function addItem(data) {
  const cartId = cookies().get('cartId')?.value
  await saveToDb({ cartId, data })
}
app/add-to-cart.js 'use client'
 
import { addItem } from './actions.js'
 
// Server Action being called inside a Client Component
export default function AddToCart({ productId }) {
  return (
    <form action={addItem}>
      <button type="submit">Add to Cart</button>
    </form>
  )
}
Good to know:
Using Server Actions will opt into running the React experimental channel.
React Actions, useOptimistic, and useFormStatus are not a Next.js or React Server Components specific features.
Next.js integrates React Actions into the Next.js router, bundler, and caching system, including adding data mutation APIs like revalidateTag and revalidatePath.
Convention
You can enable Server Actions in your Next.js project by enabling the experimental serverActions flag.
next.config.js module.exports = {
  experimental: {
    serverActions: true,
  },
}
Creation
Server Actions can be defined in two places:
Inside the component that uses it (Server Components only)
In a separate file (Client and Server Components), for reusability. You can define multiple Server Actions in a single file.
With Server Components
Create a Server Action by defining an asynchronous function with the "use server" directive at the top of the function body. This function should have serializable arguments and a serializable return value based on the React Server Components protocol.
app/server-component.js export default function ServerComponent() {
  async function myAction() {
app/server-component.js export default function ServerComponent() {
  async function myAction() {
    'use server'
    // ...
  }
}
With Client Components
If you're using a Server Action inside a Client Component, create your action in a separate file with the "use server" directive at the top of the file. Then, import the Server Action into your Client Component:
app/actions.js 'use server'
 
export async function myAction() {
  // ...
}
app/client-component.js 'use client'
 
import { myAction } from './actions'
 
export default function ClientComponent() {
  return (
    <form action={myAction}>
      <button type="submit">Add to Cart</button>
    </form>
  )
}
</form>
  )
}
Good to know: When using a top-level "use server" directive, all exports below will be considered Server Actions. You can have multiple Server Actions in a single file.
Invocation
You can invoke Server Actions using the following methods:
Using action: React's action prop allows invoking a Server Action on a <form> element.
Using formAction: React's formAction prop allows handling <button>, <input type="submit">, and <input type="image"> elements in a <form>.
Custom Invocation with startTransition: Invoke Server Actions without using action or formAction by using startTransition. This method disables Progressive Enhancement.
action
You can use React's action prop to invoke a Server Action on a form element. Server Actions passed with the action prop act as asynchronous side effects in response to user interaction.
app/add-to-cart.js import { cookies } from 'next/headers'
app/add-to-cart.js import { cookies } from 'next/headers'
 
export default function AddToCart({ productId }) {
  async function addItem(data) {
    'use server'
 
    const cartId = cookies().get('cartId')?.value
    await saveToDb({ cartId, data })
  }
 
  return (
    <form action={addItem}>
      <button type="submit">Add to Cart</button>
    </form>
  )
}
Good to know: An action is similar to the HTML primitive action
formAction
You can use formAction prop to handle Form Actions on elements such as button, input type="submit", and input type="image". The formAction prop takes precedence over the form's action.
app/form.js export default function Form() {
  async function handleSubmit() {
    'use server'
    // ...
  }
async function handleSubmit() {
    'use server'
    // ...
  }
 
  async function submitImage() {
    'use server'
    // ...
  }
 
  return (
    <form action={handleSubmit}>
      <input type="text" name="name" />
      <input type="image" formAction={submitImage} />
      <button type="submit">Submit</button>
    </form>
  )
}
Good to know: A formAction is the HTML primitive formaction. React now allows you to pass functions to this attribute.
Custom invocation using startTransition
You can also invoke Server Actions without using action or formAction. You can achieve this by using startTransition provided by the useTransition hook, which can be useful if you want to use Server Actions outside of forms, buttons, or inputs.
Good to know: Using startTransition disables the out-of-the-box Progressive Enhancement.
app/components/example-client-component.js 'use client'
 
import { useTransition } from 'react'
import { addItem } from '../actions'
 
function ExampleClientComponent({ id }) {
  let [isPending, startTransition] = useTransition()
 
  return (
    <button onClick={() => startTransition(() => addItem(id))}>
      Add To Cart
    </button>
  )
}
app/actions.js 'use server'
 
export async function addItem(id) {
  await addItemToDb(id)
  // Marks all product pages for revalidating
  revalidatePath('/product/[id]')
}
Custom invocation without startTransition
If you aren't doing Server Mutations, you can directly pass the function as a prop like any other function.
app/posts/[id]/page.tsx import kv from '@vercel/kv'
import LikeButton from './like-button'
 
export default function Page({ params }: { params: { id: string } }) {
  async function increment() {
    'use server'
    await kv.incr(`post:id:${params.id}`)
  }
 
  return <LikeButton increment={increment} />
}
app/post/[id]/like-button.tsx 'use client'
 
export default function LikeButton({
  increment,
}: {
  increment: () => Promise<void>
}) {
  return (
    <button
      onClick={async () => {
        await increment()
      }}
    >
      Like
    </button>
  )
}
Enhancements
Experimental useOptimistic
</button>
  )
}
Enhancements
Experimental useOptimistic
The experimental useOptimistic hook provides a way to implement optimistic updates in your application. Optimistic updates are a technique that enhances user experience by making the app appear more responsive.
When a Server Action is invoked, the UI is updated immediately to reflect the expected outcome, instead of waiting for the Server Action's response.
app/thread.js 'use client'
 
import { experimental_useOptimistic as useOptimistic, useRef } from 'react'
import { send } from './actions.js'
 
export function Thread({ messages }) {
  const [optimisticMessages, addOptimisticMessage] = useOptimistic(
    messages,
    (state, newMessage) => [...state, { message: newMessage, sending: true }]
  )
  const formRef = useRef()
 
  return (
)
  const formRef = useRef()
 
  return (
    <div>
      {optimisticMessages.map((m) => (
        <div>
          {m.message}
          {m.sending ? 'Sending...' : ''}
        </div>
      ))}
      <form
        action={async (formData) => {
          const message = formData.get('message')
          formRef.current.reset()
          addOptimisticMessage(message)
          await send(message)
        }}
        ref={formRef}
      >
        <input type="text" name="message" />
      </form>
    </div>
  )
}
Experimental useFormStatus
The experimental useFormStatus hook can be used within Form Actions, and provides the pending property.
app/form.js 'use client'
app/form.js 'use client'
 
import { experimental_useFormStatus as useFormStatus } from 'react-dom'
 
function Submit() {
  const { pending } = useFormStatus()
 
  return (
    <input
      type="submit"
      className={pending ? 'button-pending' : 'button-normal'}
      disabled={pending}
    >
      Submit
    </input>
  )
}
Progressive Enhancement
Progressive Enhancement allows a <form> to function properly without JavaScript, or with JavaScript disabled. This allows users to interact with the form and submit data even if the JavaScript for the form hasn't been loaded yet or if it fails to load.
Both Server Form Actions and Client Form Actions support Progressive Enhancement, using one of two strategies:
If a Server Action is passed directly to a <form>, the form is interactive even if JavaScript is disabled.
If a Client Action is passed to a <form>, the form is still interactive, but the action will be placed in a queue until the form has hydrated. The <form> is prioritized with Selective Hydration, so it happens quickly.
app/components/example-client-component.js 'use client'
 
import { useState } from 'react'
import { handleSubmit } from './actions.js'
 
export default function ExampleClientComponent({ myAction }) {
  const [input, setInput] = useState()
 
  return (
    <form action={handleSubmit} onChange={(e) => setInput(e.target.value)}>
      {/* ... */}
    </form>
  )
}
In both cases, the form is interactive before hydration occurs. Although Server Actions have the additional benefit of not relying on client JavaScript, you can still compose additional behavior with Client Actions where desired without sacrificing interactivity.
Size Limitation
Size Limitation
By default, the maximum size of the request body sent to a Server Action is 1MB. This prevents large amounts of data being sent to the server, which consumes a lot of server resource to parse.
However, you can configure this limit using the experimental serverActionsBodySizeLimit option. It can take the number of bytes or any string format supported by bytes, for example 1000, '500kb' or '3mb'.
next.config.js module.exports = {
  experimental: {
    serverActions: true,
    serverActionsBodySizeLimit: '2mb',
  },
}
Examples
Usage with Client Components
Import
Server Actions cannot be defined within Client Components, but they can be imported. To use Server Actions in Client Components, you can import the action from a file containing a top-level "use server" directive.
app/actions.js 'use server'
 
export async function addItem() {
app/actions.js 'use server'
 
export async function addItem() {
  // ...
}
app/components/example-client-component.js 'use client'
 
import { useTransition } from 'react'
import { addItem } from '../actions'
 
function ExampleClientComponent({ id }) {
  let [isPending, startTransition] = useTransition()
 
  return (
    <button onClick={() => startTransition(() => addItem(id))}>
      Add To Cart
    </button>
  )
}
Props
Although importing Server Actions is recommended, in some cases you might want to pass down a Server Action to a Client Component as a prop.
For example, you might want to use a dynamically generated value within the action. In that case, passing a Server Action down as a prop might be a viable solution.
app/components/example-server-component.js import { ExampleClientComponent } from './components/example-client-component.js'
 
function ExampleServerComponent({ id }) {
  async function updateItem(data) {
    'use server'
    modifyItem({ id, data })
  }
 
  return <ExampleClientComponent updateItem={updateItem} />
}
app/components/example-client-component.js 'use client'
 
function ExampleClientComponent({ updateItem }) {
  async function action(formData) {
    await updateItem(formData)
  }
 
  return (
    <form action={action}>
      <input type="text" name="name" />
      <button type="submit">Update Item</button>
    </form>
  )
}
On-demand Revalidation
</form>
  )
}
On-demand Revalidation
Server Actions can be used to revalidate data on-demand by path (revalidatePath) or by cache tag (revalidateTag).
 import { revalidateTag } from 'next/cache'
 
async function revalidate() {
  'use server'
  revalidateTag('blog-posts')
}
Validation
The data passed to a Server Action can be validated or sanitized before invoking the action. For example, you can create a wrapper function that receives the action as its argument, and returns a function that invokes the action if it's valid.
app/actions.js 'use server'
 
import { withValidate } from 'lib/form-validation'
 
export const action = withValidate((data) => {
  // ...
})
lib/form-validation.js export function withValidate(action) {
  return async (formData) => {
    'use server'
return async (formData) => {
    'use server'
 
    const isValidData = verifyData(formData)
 
    if (!isValidData) {
      throw new Error('Invalid input.')
    }
 
    const data = process(formData)
    return action(data)
  }
}
Using headers
You can read incoming request headers such as cookies and headers within a Server Action.
 import { cookies } from 'next/headers'
 
async function addItem(data) {
  'use server'
 
  const cartId = cookies().get('cartId')?.value
 
  await saveToDb({ cartId, data })
}
Additionally, you can modify cookies within a Server Action.
 import { cookies } from 'next/headers';
 
async function create(data) {
  'use server';
 
  const cart = await createCart():
'use server';
 
  const cart = await createCart():
  cookies().set('cartId', cart.id)
  // or
  cookies().set({
    name: 'cartId',
    value: cart.id,
    httpOnly: true,
    path: '/'
  })
}
Glossary
Actions
Actions are an experimental feature in React, allowing you to run async code in response to a user interaction.
Actions are not Next.js or React Server Components specific, however, they are not yet available in the stable version of React. When using Actions through Next.js, you are opting into using the React experimental channel.
Actions are defined through the action prop on an element. Typically when building HTML forms, you pass a URL to the action prop. With Actions, React now allows you to pass a function directly.
React also provides built-in solutions for optimistic updates with Actions. It's important to note new patterns are still being developed and new APIs may still be added.
Form Actions
Actions integrated into the web standard <form> API, and enable out-of-the-box progressive enhancement and loading states. Similar to the HTML primitive formaction.
Server Functions
Functions that run on the server, but can be called on the client.
Server Actions
Server Functions called as an action.
Server Actions can be progressively enhanced by passing them to a form element's action prop. The form is interactive before any client-side JavaScript has loaded. This means React hydration is not required for the form to submit.
Server Mutations
Server Actions that mutates your data and calls redirect, revalidatePath, or revalidateTag.
Data FetchingThe Next.js App Router allows you to fetch data directly in your React components by marking the function as async and using await for the Promise.
Data fetching is built on top of the fetch() Web API and React Server Components. When using fetch(), requests are automatically deduped by default.
Next.js extends the fetch options object to allow each request to set its own caching and revalidating.
async and await in Server Components
You can use async and await to fetch data in Server Components.
app/page.tsx async function getData() {
  const res = await fetch('https://api.example.com/...')
  // The return value is *not* serialized
  // You can return Date, Map, Set, etc.
 
  // Recommendation: handle errors
  if (!res.ok) {
    // This will activate the closest `error.js` Error Boundary
    throw new Error('Failed to fetch data')