Redirects Next Js

Master URL redirection in Next.js with next.config.js, middleware, and App Router methods. Complete guide with code examples and performance best practices.

Why Redirects Matter in Next.js

URL redirects serve multiple critical functions in web development. When restructuring a website, migrating content, or fixing broken links, redirects preserve the user experience and maintain search engine rankings. Next.js provides several methods for implementing redirects, each suited to different scenarios and performance requirements.

The framework's built-in redirect capabilities integrate directly with the server and edge network, ensuring that redirects happen as early as possible in the request lifecycle. This approach minimizes latency and prevents unnecessary client-side operations. Understanding when and how to use each redirect method is essential for building performant Next.js applications.

Key Benefits of Next.js Redirects

  • SEO preservation: Search engines recognize redirected URLs and transfer ranking signals
  • User experience: Visitors reach their intended destination without encountering errors
  • Site migration: Consolidate multiple URLs or restructure sections without losing traffic
  • A/B testing: Route users to different versions of pages for experimentation
  • Maintenance: Temporarily redirect pages during updates or maintenance windows

Common Redirect Scenarios

Modern web applications frequently require redirects for various reasons. Content management systems often need to redirect old article URLs to new locations after reorganizing content structure. E-commerce platforms redirect outdated product pages to current inventory or category pages. Marketing campaigns frequently use tracked URLs that redirect to landing pages, and these need to remain functional even after campaigns end.

Temporary redirects (302, 307) signal to browsers and search engines that the redirect is temporary, while permanent redirects (301) indicate a permanent change. This distinction affects how search engines handle indexing and can impact SEO performance over time.

For more on building SEO-friendly web applications, explore our web development services and learn how proper routing strategies contribute to search visibility.

Method 1: next.config.js Redirects

The next.config.js file provides the most straightforward method for defining redirects in Next.js applications. This configuration-based approach defines redirects at build time, making them highly performant because they are compiled directly into the application.

Basic Redirect Configuration

Redirects in next.config.js are defined using an async function that returns an array of redirect objects. Each redirect specifies a source path (the URL to match), a destination path (where to redirect), and a permanent flag indicating whether the redirect is temporary or permanent.

// next.config.js
module.exports = {
 async redirects() {
 return [
 {
 source: '/old-page',
 destination: '/new-page',
 permanent: true,
 },
 {
 source: '/temporary',
 destination: '/other',
 permanent: false,
 },
 ]
 },
}

The permanent property determines the HTTP status code. Setting permanent: true generates a 301 status code, which browsers cache indefinitely and search engines recognize as a permanent change. Setting permanent: false generates a 307 status code for temporary redirects.

Dynamic Path Matching

One of the most powerful features of next.config.js redirects is the ability to match dynamic path segments. Using named parameters, you can capture portions of the URL and use them in the destination. This pattern matching approach aligns with how Next.js handles dynamic routing for flexible URL structures.

async redirects() {
 return [
 {
 source: '/blog/:slug',
 destination: '/articles/:slug',
 permanent: true,
 },
 {
 source: '/docs/:version/:chapter*',
 destination: '/documentation/:version/:chapter*',
 permanent: true,
 },
 {
 source: '/users/:userId/posts/:postId',
 destination: '/profile/:userId/article/:postId',
 permanent: true,
 },
 ]
}

The :slug pattern matches a single path segment, while :slug* matches multiple segments including slashes. This flexibility enables complex redirect patterns without requiring middleware.

Regex Pattern Matching

For more complex matching requirements, Next.js supports regular expression patterns. This enables precise matching based on URL patterns, query parameters, or specific formats.

async redirects() {
 return [
 {
 source: '/post/:id(\\d+)',
 destination: '/article/:id',
 permanent: true,
 },
 {
 source: '/news/:year(\\d{4})/:month(\\d{2})',
 destination: '/archive/:year/:month',
 permanent: true,
 },
 {
 source: '/((?!api|static).*)',
 destination: '/pages/:1',
 permanent: true,
 },
 ]
}

The regular expressions are placed in parentheses after the parameter name. Special regex characters like parentheses, curly braces, and colons must be escaped when used in source paths.

Conditional Redirects with has/missing

Next.js redirects support conditional matching based on request properties. The has and missing arrays enable redirects that only apply when specific conditions are met.

async redirects() {
 return [
 {
 source: '/preview/:path*',
 has: [
 {
 type: 'header',
 key: 'x-preview-mode',
 value: 'true',
 },
 ],
 destination: '/preview-mode/:path*',
 permanent: false,
 },
 {
 source: '/admin/:path*',
 missing: [
 {
 type: 'cookie',
 key: 'auth-token',
 },
 ],
 destination: '/login?redirect=/admin/:path*',
 permanent: false,
 },
 {
 source: '/search',
 has: [
 {
 type: 'query',
 key: 'q',
 },
 ],
 destination: '/results?q=:q',
 permanent: true,
 },
 ]
}

This capability enables sophisticated redirect logic based on request characteristics without requiring middleware execution.

For enterprise-scale applications, combining redirects with proper technical SEO services ensures optimal search performance during site restructurings.

Method 2: Middleware Redirects

Next.js Middleware provides a powerful way to handle redirects at the edge, before requests reach page handlers. This approach offers maximum flexibility for dynamic redirect logic that depends on runtime conditions, authentication state, or external data sources.

Middleware Function Structure

Middleware runs before any cached content, enabling redirects based on request properties, user authentication, geolocation, or any other runtime condition. This edge computing approach complements server-side rendering strategies by intercepting requests before they reach the application.

// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
 const isAuthenticated = request.cookies.has('auth-token')

 if (!isAuthenticated && request.nextUrl.pathname.startsWith('/dashboard')) {
 return NextResponse.redirect(
 new URL('/login?redirect=' + request.nextUrl.pathname, request.url)
 )
 }

 return NextResponse.next()
}

export const config = {
 matcher: '/dashboard/:path*',
}

Advanced Middleware Redirect Patterns

Middleware excels at scenarios requiring runtime evaluation. Feature flag checks, A/B testing assignments, and geolocation-based routing all benefit from middleware processing.

import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
 const response = NextResponse.next()

 const bucket = request.cookies.get('ab-test-bucket')
 if (!bucket) {
 const variant = Math.random() < 0.5 ? 'control' : 'variant'
 response.cookies.set('ab-test-bucket', variant)

 if (variant === 'variant' && request.nextUrl.pathname === '/pricing') {
 return NextResponse.redirect(new URL('/pricing-pro', request.url))
 }
 }

 const country = request.geo?.country
 if (country === 'DE' && !request.nextUrl.pathname.startsWith('/de')) {
 return NextResponse.redirect(new URL('/de' + request.nextUrl.pathname, request.url))
 }

 return response
}

Performance Considerations for Middleware

Middleware runs on every request matching the configured paths, which introduces latency compared to build-time redirects. Use middleware only when necessary and consider the performance implications.

From the Vercel discussion on redirect performance, using redirects() in next.config.js is fastest for exact routes, while middleware should be reserved for parameterized, wildcard, or regex patterns requiring runtime evaluation. This hybrid approach optimizes performance while maintaining flexibility.

Middleware is particularly valuable for custom web application development requiring sophisticated routing logic based on user context and behavior.

Method 3: App Router redirect Function

The App Router introduces a redirect() function for use in Server Components and Server Actions. This approach integrates redirects directly into the application logic, enabling conditional redirects based on business rules.

Using redirect in Server Components

// app/admin/page.tsx
import { redirect } from 'next/navigation'
import { getUserSession } from '@/lib/auth'

export default async function AdminPage() {
 const session = await getUserSession()

 if (!session) {
 redirect('/login')
 }

 if (!session.isAdmin) {
 redirect('/unauthorized')
 }

 return <AdminDashboard />
}

The redirect() function immediately terminates the current execution and sends a redirect response. It can be called from any Server Component or Server Action where you have access to the necessary data for making the redirect decision.

Redirect with NotFound Fallback

// app/products/[slug]/page.tsx
import { redirect, notFound } from 'next/navigation'
import { getProduct } from '@/lib/products'

export default async function ProductPage({ params }: { params: { slug: string } }) {
 const product = await getProduct(params.slug)

 if (!product) {
 notFound()
 }

 if (product.status === 'discontinued') {
 redirect(`/products/${product.replacementSlug}`)
 }

 return <ProductDetails product={product} />
}

Combining redirect() with notFound() from Next.js navigation provides a clean way to handle edge cases like discontinued products or removed content while maintaining proper HTTP responses.

This approach works seamlessly with our React development services for building modern, server-rendered applications with robust navigation handling. Understanding how z-index and other CSS properties interact with routing can help you build more sophisticated page layouts.

Method 4: Client-Side Redirects

Client-side redirects occur in the browser after JavaScript execution. While they do not provide the same SEO benefits as server-side redirects, they remain useful for navigation within client-side applications and handling user interactions.

Using useRouter Hook

'use client'

import { useRouter } from 'next/navigation'

export function LoginForm() {
 const router = useRouter()

 async function handleSubmit(event: React.FormEvent) {
 event.preventDefault()

 const success = await loginUser()

 if (success) {
 router.push('/dashboard')
 } else {
 router.push('/login?error=invalid')
 }
 }

 return <form onSubmit={handleSubmit}>{/* form fields */}</form>
}

The router.push() method adds a new entry to the browser history, enabling back-button navigation. For immediate redirects without history entries, use router.replace().

When to Use Client-Side Redirects

Client-side redirects are appropriate for handling form submissions, user interactions, and conditional navigation after client-side state changes. However, they have significant limitations for SEO and initial page loads. Search engines may not follow client-side redirects reliably, and users experience a brief flash of the source page before the redirect occurs.

Use client-side redirects for authenticated routes, post-login navigation, and user-guided transitions. Use server-side redirects for SEO-critical scenarios, URL normalization, and any redirect that should occur before page rendering. For single-page applications, understanding how React routing differs from server-side approaches is essential.

For applications requiring both client-side interactivity and SEO optimization, our full-stack development services combine the best of both approaches.

Performance Best Practices

Build-Time vs Runtime Redirects

Redirects defined in next.config.js are evaluated at build time and compiled into the application. This makes them the fastest option because no additional computation is required during request processing. Middleware redirects require edge function execution on each matching request, introducing latency proportional to the middleware's complexity.

For applications with thousands of redirects, the Next.js documentation recommends limiting next.config.js redirects to approximately 1,000 entries. Beyond this threshold, consider using a middleware-based solution with external data storage, such as a database or CMS, to manage redirect rules dynamically.

Caching and TTL Considerations

Permanent redirects (301) are cached by browsers indefinitely, which improves subsequent request performance but makes testing difficult during development. Temporary redirects (307) are not cached, ensuring that each request evaluates the redirect logic.

During development, use temporary redirects (permanent: false) to avoid caching issues. Switch to permanent redirects only after thoroughly testing the redirect behavior in a staging environment.

Redirect Order and Matching Priority

Next.js processes redirects in the order they are defined, with the first matching redirect taking effect. This sequential processing means that more specific redirects should be defined before general patterns:

async redirects() {
 return [
 {
 source: '/old-popular-article',
 destination: '/new-location',
 permanent: true,
 },
 {
 source: '/blog/:slug',
 destination: '/articles/:slug',
 permanent: true,
 },
 ]
}

Always define specific redirects before catch-all patterns to ensure precise matching behavior. This priority system is similar to how device-width media queries are evaluated in responsive design, where specificity determines which rules apply.

Optimizing redirects is just one aspect of performance optimization that contributes to overall site speed and user experience.

SEO Implications

Link Equity Transfer

HTTP 301 redirects signal to search engines that a page has permanently moved. This status code enables the transfer of link equity (ranking signals from backlinks) from the old URL to the new URL. HTTP 302 and 307 redirects indicate temporary moves, and search engines typically do not transfer link equity in these cases.

For permanent site restructurings, always use permanent: true in next.config.js redirects to preserve search rankings. Reserve temporary redirects for seasonal content, A/B testing, or situations where the original URL may be restored.

Handling Redirect Chains

Avoid creating redirect chains where one redirect points to another redirected URL. Each additional hop loses some link equity and introduces latency. Audit redirect configurations regularly to identify and consolidate chains into single-step redirects.

Tools like Screaming Frog can crawl websites and identify redirect chains, enabling systematic cleanup of inefficient redirect patterns. Regular monitoring is essential for maintaining optimal site performance.

Proper redirect strategy is essential for maintaining search visibility during site migrations. Our SEO services include comprehensive redirect planning to protect your search rankings during any site restructuring.

For larger applications, consider implementing a redirect monitoring system as part of your ongoing technical maintenance to catch and fix redirect chains before they impact SEO performance.

Common Patterns and Use Cases

www to Non-www Redirect

async redirects() {
 return [
 {
 source: '/:path*',
 has: [
 {
 type: 'host',
 value: 'www.example.com',
 },
 ],
 destination: 'https://example.com/:path*',
 permanent: true,
 },
 ]
}

HTTP to HTTPS Redirect

async redirects() {
 return [
 {
 source: '/:path*',
 has: [
 {
 type: 'host',
 value: 'example.com',
 },
 ],
 destination: 'https://example.com/:path*',
 permanent: true,
 },
 ]
}

Trailing Slash Normalization

async redirects() {
 return [
 {
 source: '/blog/:slug([^/]+)',
 destination: '/blog/:slug/',
 permanent: true,
 },
 ]
}

Localized Path Redirects

async redirects() {
 return [
 {
 source: '/en/:path*',
 destination: '/:path*',
 locale: false,
 permanent: true,
 },
 ]
}

These patterns cover common requirements for domain canonicalization, security enforcement, URL consistency, and internationalization. Implementing these redirects at the edge ensures fast, reliable handling without client-side overhead.

For multi-site deployments, our custom development services can help architect comprehensive redirect strategies that maintain SEO value across all domains and locales. Similar to how animation-duration affects visual performance, proper redirect configuration impacts site load performance.

Debugging and Testing

Using curl for Testing

Test redirects using curl to inspect HTTP status codes and response headers:

# Check redirect status and location
curl -I http://localhost:3000/old-page

# Follow redirects and show final URL
curl -L -s -o /dev/null -w "%{url_effective}\n" http://localhost:3000/old-page

# Verbose output showing all hops
curl -v http://localhost:3000/old-page 2>&1 | grep -E "(< HTTP|< Location)"

Browser DevTools

Browser developer tools provide visual confirmation of redirect behavior. The Network tab displays each redirect as a separate request, showing the status code and Location header for each step. This view helps identify unexpected redirect chains or loops.

Automated Testing

For production applications, integrate redirect testing into your CI/CD pipeline. Write tests that verify redirect behavior for critical paths:

// example.test.ts
import { setup, fetch } from '@playwright/test'

test('critical redirects work correctly', async () => {
 const response = await fetch('/old-page')
 expect(response.status()).toBe(301)
 expect(response.headers().location).toBe('/new-page')
})

Regular testing ensures that redirects continue functioning correctly after code changes and deployments. Just as console-api helps debug JavaScript, proper testing tools help validate redirect behavior.

Establishing a comprehensive testing strategy is part of our quality assurance process for delivering reliable web applications.

Frequently Asked Questions

When should I use next.config.js redirects vs middleware?

Use next.config.js redirects for static, build-time known redirects--they offer the best performance. Use middleware for dynamic redirects that require runtime evaluation, such as authentication checks, A/B testing, or redirects based on external data.

What's the difference between 301 and 302 redirects?

A 301 redirect indicates a permanent move and is cached by browsers indefinitely. It transfers SEO link equity to the destination. A 302 (or 307) indicates a temporary move and is not cached, preserving the original URL for future use.

Can I redirect query parameters in Next.js?

Yes, you can match and preserve query parameters using the `has` condition with type 'query' in next.config.js, or access them programmatically in middleware and pass them to the destination URL.

How many redirects can I define in next.config.js?

Next.js can handle thousands of redirects, but performance may degrade with very large arrays. For applications with 1,000+ redirects, consider using middleware with an external data source for dynamic redirect management.

Need Help with Next.js Redirects?

Our team specializes in building performant Next.js applications with proper redirect strategies for SEO and user experience.