permanentRedirect default behavior for type parameter
By default, permanentRedirect uses 'push' (adding a new entry to the browser history stack) in Server Actions and 'replace' (replacing the current URL in the browser history stack) everywhere else.
permanentRedirect usage contexts
permanentRedirect can be used in Server Components, Client Components, Route Handlers, and Server Functions (also called Server Actions).
permanentRedirect in streaming context
When used in a streaming context, permanentRedirect inserts a meta tag to emit the redirect on the client side.
permanentRedirect HTTP redirect codes
In a Server Action, permanentRedirect performs a client-side navigation when JavaScript is available. For progressive enhancement form submissions, it serves a 303 HTTP redirect response. Otherwise, it serves a 308 (Permanent) HTTP redirect response.
permanentRedirect throws NEXT_REDIRECT error
Invoking permanentRedirect throws a NEXT_REDIRECT error and terminates rendering of the route segment in which it was thrown. It does not require using 'return permanentRedirect()' as it uses the TypeScript 'never' type.
permanentRedirect vs redirect function
permanentRedirect returns a 308 (Permanent) HTTP redirect response by default. The redirect function returns a 307 (Temporary) HTTP redirect response instead and should be used for temporary redirects.
permanentRedirect when resource doesn't exist
If a resource doesn't exist, use the notFound function instead of permanentRedirect.
RedirectType import and usage
Import RedirectType from 'next/navigation' to specify redirect behavior. Example: permanentRedirect('/redirect-to', RedirectType.replace) or permanentRedirect('/redirect-to', RedirectType.push).
revalidatePath function signature and parameters
revalidatePath(path: string, type?: 'page' | 'layout'): void. The path parameter is a string representing your route file structure, either a literal path like /product/123 or a route pattern with dynamic segments like /product/[slug]. Do not append /page or /layout. The path must not exceed 1024 characters, is case-sensitive, and does not require a trailing slash. The type parameter is optional and accepts 'page' or 'layout' to change the type of path to revalidate. If path contains a dynamic segment, the type parameter is required. If path is a literal path, omit type. The function does not return a value.
revalidatePath behavior in Route Handlers
When called in Route Handlers, revalidatePath marks the path for revalidation. The revalidation is done on the next visit to the specified path. Calling revalidatePath with a dynamic route segment will not immediately trigger many revalidations at once; the invalidation only happens when the path is next visited.
revalidatePath example: Server Function usage
'use server'
import { revalidatePath } from 'next/cache'
export default async function submit() {
await submitForm()
revalidatePath('/')
}
This example shows revalidatePath called within a Server Function in app/actions.ts.
revalidatePath example: Route Handler usage
import { revalidatePath } from 'next/cache'
import type { NextRequest } from 'next/server'
export async function GET(request: NextRequest) {
const path = request.nextUrl.searchParams.get('path')
if (path) {
revalidatePath(path)
return Response.json({ revalidated: true, now: Date.now() })
}
return Response.json({
revalidated: false,
now: Date.now(),
message: 'Missing path to revalidate',
})
}
This example shows revalidatePath called within a Route Handler in app/api/revalidate/route.ts.
revalidatePath can only be called in Server Functions and Route Handlers
revalidatePath cannot be called in Client Components or Proxy, as it only works in server environments. It can be called in Server Functions and Route Handlers.
revalidatePath behavior in Server Functions
When called in Server Functions, revalidatePath updates the UI immediately if viewing the affected path. Currently, it also causes all previously visited pages to refresh when navigated to again, though this behavior is temporary and will be updated in the future to apply only to the specific path.
What revalidatePath can invalidate
The path parameter can point to pages, layouts, or route handlers. Pages: invalidates the specific page. Layouts: invalidates the layout (the layout.tsx at that segment), all nested layouts beneath it, and all pages beneath them. Route Handlers: invalidates cached data accessed within route handlers.
revalidatePath with rewrites uses destination path
When using rewrites, you must pass the destination path (the actual route file location), not the source path that appears in the browser's address bar. Cache entries are tagged based on which route file renders them, so revalidatePath operates on the route file structure, not the URL visible to users. For example, if you have a rewrite from /blog to /news, call revalidatePath('/news'), not revalidatePath('/blog').
Difference between revalidatePath, revalidateTag, and updateTag
revalidatePath invalidates a specific page or layout path. revalidateTag marks data with specific tags as stale and applies across all pages that use those tags. updateTag expires data with specific tags and applies across all pages that use those tags. When you call revalidatePath, only the specified path gets fresh data on the next visit. Other pages that use the same data tags will continue to serve cached data until those specific tags are also revalidated.
revalidatePath example: revalidate a specific path
import { revalidatePath } from 'next/cache'
revalidatePath('/blog/post-1')
This will invalidate one specific path for revalidation on the next page visit.
revalidatePath example: revalidate a Page path with dynamic segments
import { revalidatePath } from 'next/cache'
revalidatePath('/blog/[slug]', 'page')
// or with route groups
revalidatePath('/(main)/blog/[slug]', 'page')
This will invalidate any path that matches the provided page file for revalidation on the next page visit. This will not invalidate pages beneath the specific page. For example, /blog/[slug] won't invalidate /blog/[slug]/[author].
revalidatePath example: revalidate a Layout path
import { revalidatePath } from 'next/cache'
revalidatePath('/blog/[slug]', 'layout')
// or with route groups
revalidatePath('/(main)/post/[slug]', 'layout')
This will invalidate any path that matches the provided layout file for revalidation on the next page visit. This will cause pages beneath with the same layout to be invalidated and revalidated on the next visit. For example, /blog/[slug]/[another] would also be invalidated and revalidated on the next visit.
revalidatePath and updateTag used together in utility functions
'use server'
import { revalidatePath, updateTag } from 'next/cache'
export async function updatePost() {
await updatePostInDatabase()
revalidatePath('/blog')
updateTag('posts')
}
This pattern ensures that both the specific page and any other pages using the same data remain consistent. revalidatePath and updateTag are complementary primitives often used together to ensure comprehensive data consistency across your application.
revalidatePath example: revalidate all data
import { revalidatePath } from 'next/cache'
revalidatePath('/', 'layout')
This will purge the Client Cache and invalidate all cached data for revalidation on the next page visit.
redirect in Client Component via Server Action
To use redirect in a Client Component through a Server Action: Client Component: 'use client'
import { navigate } from './actions'
export function ClientRedirect() {
return (
<form action={navigate}>
<input type="text" name="id" />
<button>Submit</button>
</form>
)
}
Server Action (app/actions.ts): 'use server'
import { redirect } from 'next/navigation'
export async function navigate(data: FormData) {
redirect(`/posts/${data.get('id')}`)
}
redirect function overview
The redirect function allows you to redirect the user to another URL. It can be used while rendering in Server Components, Client Components, Route Handlers, and Server Functions. When used in a streaming context, this inserts a meta tag to emit the redirect on the client side. In a Server Action, redirect performs a client-side navigation when JavaScript is available. For progressive enhancement form submissions, it serves a 303 HTTP redirect response. Otherwise, it serves a 307 HTTP redirect response.
redirect function signature
The redirect function accepts two arguments: redirect(path, type). The path parameter is a string representing the URL to redirect to, which can be a relative or absolute path. The type parameter is either 'replace' (default) or 'push' (default in Server Actions), specifying the type of redirect to perform.
redirect type parameter behavior
By default, redirect uses 'push' (adding a new entry to the browser history stack) in Server Actions and 'replace' (replacing the current URL in the browser history stack) everywhere else. You can override this behavior by specifying the type parameter. The type parameter has no effect when used in Server Components.
redirect return value
The redirect function does not return a value.
redirect throws error and must be outside try block
The redirect function throws an error, specifically a NEXT_REDIRECT error that terminates rendering of the route segment in which it was thrown. It should be called outside the try block when using try/catch statements in Server Actions and Route Handlers. It does not require you to use return redirect() as it uses the TypeScript never type.
redirect in Client Components restrictions
The redirect function can be called in Client Components during the rendering process but not in event handlers. When using redirect in a Client Component on initial page load during Server-Side Rendering (SSR), it will perform a server-side redirect. For event handlers, use the useRouter hook instead.
redirect supports absolute URLs and external links
The redirect function accepts absolute URLs and can be used to redirect to external links.
redirect alternatives for different scenarios
If a resource doesn't exist, use the notFound function instead. If you prefer a 308 (Permanent) HTTP redirect instead of 307 (Temporary), use the permanentRedirect function. If you'd like to redirect before the render process, use next.config.js or Proxy.
redirect HTTP status codes and method preservation
The redirect function uses 307 for temporary redirects by default, which preserves the request method as POST. For permanent redirects, permanentRedirect uses 308. Server Action form submissions use 303 so the browser follows the redirect with a GET request. When JavaScript is available, Server Actions perform a client-side navigation instead of an HTTP redirect. The 307 and 308 status codes were chosen because older 302 and 301 codes would change POST requests to GET requests, which could break form submissions.
redirect import statement
To use redirect and RedirectType, import them from 'next/navigation': import { redirect, RedirectType } from 'next/navigation'. Then use redirect('/path', RedirectType.replace) or redirect('/path', RedirectType.push).
redirect in Server Component example
Example of using redirect in a Server Component: import { redirect } from 'next/navigation'
async function fetchTeam(id: string) {
const res = await fetch('https://...')
if (!res.ok) return undefined
return res.json()
}
export default async function Profile({
params,
}: {
params: Promise<{ id: string }>
}) {
const { id } = await params
const team = await fetchTeam(id)
if (!team) {
redirect('/login')
}
// ...
}
redirect in Client Component during rendering
Example of using redirect in a Client Component during rendering: 'use client'
import { redirect, usePathname } from 'next/navigation'
export function ClientRedirect() {
const pathname = usePathname()
if (pathname.startsWith('/admin') && !pathname.includes('/login')) {
redirect('/admin/login')
}
return <div>Login Page</div>
}
unauthorized example in Server Action
Example: 'use server'; import { verifySession } from '@/app/lib/dal'; import { unauthorized } from 'next/navigation'; export async function updateProfile(data: FormData) { const session = await verifySession(); if (!session) { unauthorized(); } }
unauthorized has never return type, no need for return statement
The unauthorized function has a TypeScript never return type, so execution stops without returning. You do not need to write return unauthorized(). Wrapping it in a try/catch suppresses the interrupt and no unauthorized UI renders.
unauthorized example in Route Handler
Example: import { NextRequest, NextResponse } from 'next/server'; import { verifySession } from '@/app/lib/dal'; import { unauthorized } from 'next/navigation'; export async function GET(req: NextRequest): Promise<NextResponse> { const session = await verifySession(); if (!session) { unauthorized(); } }
unauthorized with Suspense streaming pattern
To keep a page shell and loading UI visible while session verification happens, place the auth check in a Data Access Layer function inside a component wrapped in <Suspense>. This allows the shell to stream while the session resolves, and the unauthorized UI renders in place of streamed content.
unauthorized cannot be called in root layout
The unauthorized function cannot be called in the root layout.
unauthorized callable in Server Components, Server Functions, and Route Handlers
The unauthorized function can be invoked in Server Components, Server Functions (Server Actions), and Route Handlers.
unauthorized must be called in render path
The unauthorized function must be called in the render path: a component, or a function a component awaits. A call left in an un-awaited promise throws where nothing catches it, and no unauthorized UI renders.
unauthorized injects noindex meta tag
Next.js automatically injects a <meta name="robots" content="noindex" /> tag when unauthorized() is called, so the 401 page is not indexed by search engines.
unauthorized requires authInterrupts config enabled
To use the unauthorized function, enable the experimental authInterrupts configuration option in next.config.js or next.config.ts: experimental: { authInterrupts: true }
unauthorized function throws 401 error
The unauthorized() function throws an error that renders a Next.js 401 page. It throws a NEXT_HTTP_ERROR_FALLBACK;401 error and terminates rendering of the route segment where it was thrown.
unauthorized introduced in v15.1.0
The unauthorized function was introduced in Next.js version 15.1.0.
unauthorized customized with unauthorized.js file
The UI rendered when unauthorized() is called is customized using an unauthorized.js (or unauthorized.tsx) file in the file conventions.
unauthorized status code after streaming started remains 200
When unauthorized() is called inside a Suspense boundary after the response has already begun streaming as a 200, the HTTP status code cannot change and remains 200. To return a real 401 status, the auth check must run before the response streams, such as in a proxy file.
unauthorized example in Server Component
Example: import { verifySession } from '@/app/lib/dal'; import { unauthorized } from 'next/navigation'; export default async function DashboardPage() { const session = await verifySession(); if (!session) { unauthorized(); } return (<main><h1>Welcome to the Dashboard</h1><p>Hi, {session.user.name}.</p></main>); }
revalidateTag use case
revalidateTag is ideal for content where a slight delay in updates is acceptable, such as blog posts, product catalogs, or documentation. Users receive stale content while fresh data loads in the background.
revalidateTag Route Handler example
Example of revalidateTag in a Route Handler: import type { NextRequest } from 'next/server'; import { revalidateTag } from 'next/cache'; export async function GET(request: NextRequest) { const tag = request.nextUrl.searchParams.get('tag'); if (tag) { revalidateTag(tag, 'max'); return Response.json({ revalidated: true, now: Date.now() }); } return Response.json({ revalidated: false, now: Date.now(), message: 'Missing tag to revalidate', }); }
Single-argument revalidateTag form is deprecated
The single-argument form revalidateTag(tag) is deprecated. It currently works if TypeScript errors are suppressed, but this behavior may be removed in a future version. You should update to the two-argument signature.
revalidateTag function signature and parameters
revalidateTag(tag: string, profile: string | { expire?: number }): void. The tag parameter is a string representing the cache tag, must not exceed 256 characters, is case-sensitive. The profile parameter is a string specifying revalidation behavior, with recommended value "max" for stale-while-revalidate semantics, or any default/custom profiles defined in cacheLife. Alternatively pass an object with an optional expire property for custom expiration behavior.
revalidateTag with profile="max" behavior
When using profile="max" (recommended), the tag entry is marked as stale, and the next time a resource with that tag is visited, it will use stale-while-revalidate semantics. The stale content is served while fresh content is fetched in the background. Calling revalidateTag with profile="max" does not immediately trigger many revalidations at once; the invalidation only happens when any page using that tag is next visited.
revalidateTag with custom cache life profile
For advanced usage, you can specify any cache life profile that your application has defined as the profile parameter to revalidateTag, allowing for custom revalidation behaviors tailored to specific caching requirements.
revalidateTag without profile parameter (deprecated)
Calling revalidateTag with only the tag argument (deprecated form) will expire the tag entry immediately, and the next request to that resource will be a blocking revalidate/cache miss. This behavior is deprecated; you should either use profile="max" or migrate to updateTag.
revalidateTag with expire: 0 for immediate expiration
You can pass { expire: 0 } as the second argument to revalidateTag: revalidateTag(tag, { expire: 0 }). This pattern is necessary when external systems like webhooks or third-party services call your Route Handlers and require data to expire immediately.
revalidateTag callable contexts
revalidateTag can be called in Server Functions and Route Handlers. It cannot be called in Client Components or Proxy, as it only works in server environments.
revalidateTag does not return a value
revalidateTag returns void; it does not return any value.
revalidateTag vs revalidatePath
revalidateTag invalidates data with specific tags across all pages that use those tags, while revalidatePath invalidates specific page or layout paths. These functions serve different purposes and may need to be used together for comprehensive data consistency.