javascript
37 lines · 7 steps
How redirects work in Next.js config
A Next.js config builds a redirect table by combining a data-driven list with hand-written rules that use path params, query conditions, and regex.
Explained by
highlit
1const legacyRedirects = [
2 { from: '/blog/:slug', to: '/articles/:slug' },
3 { from: '/shop/product/:id', to: '/store/items/:id' },
4 { from: '/about-us', to: '/about' },
5 { from: '/help/faq', to: '/support/faq' },
6];
7
8/** @type {import('next').NextConfig} */
9const nextConfig = {
10 async redirects() {
11 return [
12 ...legacyRedirects.map(({ from, to }) => ({
13 source: from,
14 destination: to,
15 permanent: true,
16 })),
17 {
18 source: '/docs/:path*',
19 destination: 'https://docs.example.com/:path*',
20 permanent: true,
21 },
22 {
23 source: '/user/:id/profile',
24 has: [{ type: 'query', key: 'legacy', value: 'true' }],
25 destination: '/accounts/:id',
26 permanent: true,
27 },
28 {
29 source: '/:locale(en|de|fr)/news/:slug',
30 destination: '/:locale/press/:slug',
31 permanent: true,
32 },
33 ];
34 },
35};
36
37module.exports = nextConfig;
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Storing redirect pairs as data lets you generate config entries with a single map instead of repeating boilerplate.
- 2Next.js redirect sources support named params, wildcards, query conditions via has, and inline regex for precise matching.
- 3permanent: true emits a 308 so browsers and search engines cache the redirect, which matters for SEO on migrated URLs.
Related explainers
typescript
import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import * as Joi from 'joi';
Validating env config at boot in NestJS
configuration
schema-validation
environment-variables
Intermediate
8 steps
ruby
class UserAgentParser BROWSERS = [ [/Edg\/([\d.]+)/, "Edge"], [/OPR\/([\d.]+)/, "Opera"],
Parsing user-agent strings in Ruby
regex
pattern-matching
lookup-tables
Intermediate
8 steps
javascript
function evaluate(expression) { const tokens = tokenize(expression); let pos = 0;
Building a recursive descent calculator
parsing
recursion
operator-precedence
Intermediate
8 steps
javascript
import { useState, useEffect, useCallback, useRef } from 'react'; const cache = new Map(); const inflight = new Map();
Building a stale-while-revalidate hook in React
caching
request-deduplication
custom-hooks
Advanced
10 steps
javascript
import { useEffect, useRef, useState } from 'react'; export function useDelayedFlag(active, delay = 300) { const [visible, setVisible] = useState(false);
Delaying a loading spinner with a React hook
custom-hooks
debouncing
cleanup
Intermediate
8 steps
javascript
const SWIPE_THRESHOLD = 80; const MAX_TRANSLATE = 120; export function attachSwipeToDismiss(element, onDismiss) {
Building a swipe-to-dismiss gesture in JS
touch-events
gesture-detection
dom-manipulation
Intermediate
10 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/how-redirects-work-in-next-js-config-explained-javascript-9d00/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.