How to Implement a React Router Redirect in Next.js: 6 Methods Explained
Next.js provides six distinct mechanisms for handling react router redirects, ranging from client-side navigation with router.push to server-side redirects in getServerSideProps and the App Router's redirect() function, each optimized for different rendering phases and SEO requirements.
Implementing a react router redirect in a Next.js application requires selecting the appropriate method based on when and where the redirect decision must occur. The Vercel-maintained Next.js repository offers multiple first-class redirect APIs that operate at different stages of the request lifecycle, from the edge to the client browser.
Client-Side React Router Redirect Methods
Client-side redirects occur after the initial page load and provide immediate navigation without server round-trips.
Using router.push and router.replace
The singleton router exposed by next/router provides imperative navigation methods defined in packages/next/src/client/router.ts. The coreMethodFields array (lines 58-64) defines the available methods including push and replace:
// packages/next/src/client/router.ts
const coreMethodFields = [
'push',
'replace',
'reload',
'back',
'prefetch',
'beforePopState',
] as const;
coreMethodFields.forEach((field) => {
(singletonRouter as any)[field] = (...args: any[]) =>
getRouter()[field](...args);
});
These methods are bound to the singleton router at runtime, allowing navigation without reloading the page.
Pros:
- Instant UI updates without full page reloads
- Preserves React component state
- Supports shallow routing to avoid data fetching
Cons:
- Not SEO-friendly for initial crawls
- Requires JavaScript; fails if disabled
Using the useRouter Hook
For functional components, Next.js exposes the same router instance through the useRouter hook defined in the same file (packages/next/src/client/router.ts, lines 38-46):
import { useRouter } from 'next/router';
export default function DashboardButton() {
const router = useRouter();
const handleClick = () => {
router.replace('/dashboard');
};
return <button onClick={handleClick}>Go to Dashboard</button>;
}
Pros:
- Declarative approach fitting React hooks patterns
- Access to router properties like
pathnameandquery
Cons:
- Shares the same runtime limitations as the raw router methods
Server-Side React Router Redirect Methods
Server-side redirects occur before sending HTML to the client, making them ideal for authentication and SEO-critical navigation.
Redirects in getServerSideProps
The Pages Router supports returning a Redirect object from getServerSideProps, defined in packages/next/src/types.ts (line 70):
// packages/next/src/types.ts
export type Redirect = {
destination: string;
permanent?: boolean;
basePath?: boolean;
locale?: false | string;
};
Implementation example:
// pages/protected.tsx
export async function getServerSideProps(context) {
const { req } = context;
if (!req.headers.cookie?.includes('auth_token')) {
return {
redirect: {
destination: '/login',
permanent: false, // 307 Temporary Redirect
},
};
}
return { props: { user: 'authenticated' } };
}
Pros:
- SEO-friendly (search engines follow the HTTP redirect)
- Works without JavaScript enabled
- Supports permanent (301) and temporary (307/308) status codes
Cons:
- Incurs a server round-trip latency
- Cannot preserve client-side React state
- Limited to the Pages Router (not available in App Router)
Static Config Redirects in next.config.js
For global, build-time redirects, Next.js compiles redirect rules defined in next.config.js using the same Redirect type from packages/next/src/types.ts:
// next.config.js
module.exports = {
async redirects() {
return [
{
source: '/old-blog/:slug',
destination: '/blog/:slug',
permanent: true, // 301 redirect
},
{
source: '/api/v1/:path*',
destination: '/api/v2/:path*',
permanent: false,
},
];
},
};
Pros:
- Fast execution at the edge or routing layer
- Applies to all routes (Pages, API, and App Router)
- No runtime JavaScript required
Cons:
- Requires a build step to update
- Not dynamic per-request (cannot access cookies or headers at build time)
App Router React Router Redirect Methods
The App Router (app/ directory) introduces new APIs optimized for Server Components and streaming architecture.
Using redirect and permanentRedirect
The next/navigation module exports redirect and permanentRedirect functions implemented in packages/next/src/client/components/redirect.ts. These functions throw a specially crafted error that the runtime catches to emit the appropriate HTTP response:
// packages/next/src/client/components/redirect.ts
export function redirect(url: string, type?: RedirectType): never {
type ??= actionAsyncStorage?.getStore()?.isAction ? 'push' : 'replace';
throw getRedirectError(url, type, RedirectStatusCode.TemporaryRedirect);
}
Usage in a Server Component:
// app/dashboard/page.tsx
import { redirect } from 'next/navigation';
export default async function DashboardPage() {
const user = await fetchUser();
if (!user) {
redirect('/login'); // 307 Temporary Redirect
}
return <div>Welcome {user.name}</div>;
}
Usage in a Route Handler:
// app/api/auth/route.ts
import { redirect } from 'next/navigation';
export async function GET() {
// After processing auth...
redirect('/dashboard');
}
Pros:
- Works natively in Server Components without client-side JavaScript
- Available in Route Handlers and Server Actions
- Simple, declarative API
Cons:
- Limited to the App Router (not compatible with Pages Router)
- Must be called synchronously (throws an error)
- Cannot be used in client components (use
useRouterinstead)
API Route React Router Redirects
For custom API endpoints, Next.js provides a utility function to handle redirects with full control over HTTP status codes.
Using res.redirect in API Routes
The redirect utility is defined in packages/next/src/server/api-utils/index.ts (lines 59-76):
// packages/next/src/server/api-utils/index.ts
export function redirect(res, statusOrUrl, url) {
if (typeof statusOrUrl === 'string') {
url = statusOrUrl;
statusOrUrl = 307;
}
// ...
res.writeHead(statusOrUrl, { Location: url });
res.end();
return res;
}
Implementation example:
// pages/api/legacy.ts
import { redirect } from 'next/server';
export default function handler(req, res) {
// Legacy endpoint – permanently move to new location
if (req.query.version === 'v1') {
return redirect(res, 301, '/api/v2/data');
}
// Process current version
res.status(200).json({ data: 'current' });
}
Pros:
- Full control over HTTP status codes (301, 302, 307, 308)
- Works with any custom API logic
- Can access request headers and body for conditional redirects
Cons:
- Limited to API routes only
- Not suitable for page navigation (use
useRouterorredirectinstead) - Requires manual status code management
Summary
- Client-side navigation with
router.pushandrouter.replaceprovides instant UI updates in the Pages Router but requires JavaScript and lacks SEO benefits for initial crawls. - Server-side redirects via
getServerSidePropsoffer SEO-friendly HTTP redirects for the Pages Router, though they incur server latency and cannot preserve client state. - Static config redirects in
next.config.jsdeliver edge-fast performance for global URL changes but require rebuilds for updates and cannot access request-time data. - App Router redirects using
redirect()andpermanentRedirect()enable Server Component navigation with minimal boilerplate, though they are limited to the App Router architecture. - API route redirects provide full HTTP control for custom endpoints but are restricted to API handlers and require manual status code configuration.
Frequently Asked Questions
What is the difference between router.push and router.replace in Next.js?
router.push adds a new entry to the browser history stack, allowing users to navigate back to the previous page using the browser back button. router.replace replaces the current history entry instead, which is ideal for authentication flows or form submissions where you do not want users to return to the intermediate state. Both methods are defined in packages/next/src/client/router.ts and provide client-side navigation without full page reloads.
When should I use getServerSideProps redirects versus next.config.js redirects?
Use getServerSideProps redirects when you need to make dynamic decisions based on request-time data such as cookies, authentication tokens, or user sessions. This method executes on every request, allowing conditional logic but adding server latency. Use next.config.js redirects for static, global URL mappings that do not change between requests, such as legacy path migrations or domain redirects, as these are compiled into the routing layer and execute at the edge without runtime overhead.
Can I use the App Router redirect function in Client Components?
No, the redirect function from next/navigation is designed exclusively for Server Components, Route Handlers, and Server Actions within the App Router. If you attempt to use it in a Client Component, Next.js will throw an error because the function relies on server-side rendering context and throws a special error object that the runtime catches. For Client Components in the App Router, import useRouter from next/navigation and use router.push() or router.replace() instead.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →