· frameworks · 6 min read
Unlocking Next.js: Top 10 Hidden Features You Never Knew Existed
Discover 10 lesser-known Next.js features - from automatic static optimization and ISR to middleware, route handlers, next/script and next/font - with practical examples, tips and caveats to level up your Next.js apps.

Next.js hides a surprising number of productivity- and performance-boosting features that many developers either overlook or only discover after hitting scaling or performance walls. This post walks through 10 of those lesser-known capabilities with practical examples, tips and gotchas so you can start using them today.
Why these matter
These features help you ship faster, make pages faster, simplify architecture (edge functions, route handlers) and optimize runtime behavior (image/script handling, ISR). Each section includes code snippets and links to the official docs.
1) Automatic Static Optimization - when your pages are silently static
Next.js automatically statically optimizes pages that have no server-only data fetching (no getServerSideProps
, no getInitialProps
). That means a page is generated at build time without any explicit getStaticProps
call.
Tip: if you want a plain React component to be static, don’t add server-only data fetching or getInitialProps
. Conversely, adding getInitialProps
(or getServerSideProps
) opts that page into server rendering and disables automatic static optimization.
Example (static by default):
// pages/about.js
export default function About() {
return <div>About - static optimized automatically</div>;
}
Docs: https://nextjs.org/docs/advanced-features/automatic-static-optimization
Caveat: even small mistakes (using getServerSideProps
or getInitialProps
) will force SSR. Use getStaticProps
for explicit static generation when you need data at build time.
2) Incremental Static Regeneration (ISR) + On-demand revalidation
ISR lets you update static pages after build time by providing a revalidate
interval in getStaticProps
.
export async function getStaticProps() {
const posts = await fetch('https://api.example.com/posts').then(r =>
r.json()
);
return { props: { posts }, revalidate: 60 }; // stale-while-revalidate every 60s
}
On-demand revalidation lets you trigger rebuilds programmatically (useful for CMS webhooks). A serverless API route can call Next.js revalidation APIs, e.g. res.revalidate('/path')
(Pages Router) or revalidatePath()
in App Router.
Example (Pages Router API route):
// pages/api/revalidate.js
export default async function handler(req, res) {
// Protect with a token
if (req.query.secret !== process.env.MY_SECRET) {
return res.status(401).json({ message: 'Invalid token' });
}
await res.revalidate('/posts');
return res.json({ revalidated: true });
}
Docs: https://nextjs.org/docs/basic-features/data-fetching/incremental-static-regeneration
Tip: For modern App Router, revalidatePath()
and revalidateTag()
give fine-grained control (see docs). Protect revalidation endpoints with secrets to avoid abuse.
3) next/script - precise control over third-party script loading
next/script
gives you optimized loading strategies for scripts (prevent layout shifts and blocking). Strategies: beforeInteractive
, afterInteractive
(default), and lazyOnload
.
import Script from 'next/script';
export default function Page() {
return (
<>
<Script
src="https://example.com/analytics.js"
strategy="lazyOnload"
onLoad={() => console.log('analytics loaded')}
/>
</>
);
}
Why it matters: placing third-party scripts incorrectly often hurts CLS and LCP. next/script
avoids render-blocking and ensures proper ordering when needed.
Docs: https://nextjs.org/docs/basic-features/script
Caveat: beforeInteractive
is powerful but should be used sparingly (it injects scripts early and can be blocking if abused).
4) next/image - more than just responsive images
The <Image />
component automatically optimizes images (responsive sizes, modern formats, lazy loading) and supports features many developers miss:
placeholder="blur"
andblurDataURL
for low-quality placeholderspriority
to mark LCP imagessizes
andsrcSet
control for custom breakpoints- Loader plugins and
unoptimized
for special cases
Example:
import Image from 'next/image';
<Image
src="/images/hero.jpg"
alt="Hero"
width={1200}
height={800}
placeholder="blur"
blurDataURL="data:image/..."
priority
/>;
Docs: https://nextjs.org/docs/basic-features/image-optimization
Tip: Combine with next.config.js
images.domains
or use remote patterns. For heavy CMS use, consider a custom loader if your CDN provides optimized images.
5) Edge Middleware - run code at the CDN edge
Middleware runs before requests reach your app and executes on the Edge Runtime. Use it for A/B tests, authentication redirects, locale detection, and more.
Example (basic auth redirect):
// middleware.js (root)
import { NextResponse } from 'next/server';
export function middleware(request) {
const token = request.cookies.get('auth');
if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', request.url));
}
return NextResponse.next();
}
export const config = { matcher: ['/dashboard/:path*'] };
Docs: https://nextjs.org/docs/advanced-features/middleware
Caveat: Edge Runtime has some limitations (no Node APIs like fs). Keep logic simple and fast to avoid added latency.
6) Route Handlers (App Router) and Runtime selection
With the App Router you can create route.ts
/route.js
files under app/*
to define server endpoints (similar to API routes) with streaming, caching, and edge runtime support.
// app/api/hello/route.ts
import { NextResponse } from 'next/server';
export const runtime = 'edge';
export async function GET(request: Request) {
return NextResponse.json({ hello: 'world' });
}
Benefits: smaller surface area, direct usage of Request/Response web APIs, and the ability to mark runtime = 'edge'
for CDN-level execution.
Docs: https://nextjs.org/docs/app/building-your-application/routing/router-handlers
Tip: Use route handlers for API endpoints that should live close to users (auth checks, small transforms) and still integrate with App Router features like revalidatePath
.
7) next/font - zero-config font optimization
next/font
can automatically optimize Google Fonts and local fonts, handle subsetting and avoid layout shifts.
Google Fonts example:
import { Inter } from 'next/font/google';
const inter = Inter({ subsets: ['latin'], variable: '--font-inter' });
export default function App({ children }) {
return <main className={inter.className}>{children}</main>;
}
Local font example:
import localFont from 'next/font/local';
const myFont = localFont({ src: './fonts/MyFont.woff2', display: 'swap' });
Docs: https://nextjs.org/docs/basic-features/font-optimization
Caveat: next/font
is powerful but be mindful of licensing when bundling local fonts. For Google fonts, next/font/google
fetches and optimizes fonts at build time.
8) next/link prefetching behavior and shallow routing
next/link
prefetches pages automatically when a link is visible in the viewport. But you can control it:
prefetch={false}
- opt out of prefetching (useful for pages behind auth or many links)shallow
routing - change the URL without running data fetching methods again
Example (shallow routing):
import Link from 'next/link';
import { useRouter } from 'next/router';
function MyComponent() {
const router = useRouter();
return (
<button
onClick={() => router.push('/posts?page=2', undefined, { shallow: true })}
>
Next page
</button>
);
}
Docs: https://nextjs.org/docs/api-reference/next/link
Tip: disabling prefetch can reduce bandwidth on pages with many external or rarely used links.
9) Preview Mode - securely preview draft content
Preview Mode lets you render draft content (e.g., CMS drafts) without rebuilding the site. You enable preview via a secured API route that sets a preview cookie.
Example:
// pages/api/preview.js
export default function handler(req, res) {
if (req.query.secret !== process.env.PREVIEW_SECRET)
return res.status(401).end();
res.setPreviewData({});
res.writeHead(307, { Location: '/posts/preview-page' });
res.end();
}
In your data fetching (Pages), check context.preview
to fetch draft content.
Docs: https://nextjs.org/docs/advanced-features/preview-mode
Caveat: always protect preview endpoints with a secret and remove preview cookies (use res.clearPreviewData()
) after use.
10) Redirects, Rewrites, and Headers via next.config.js
Instead of using a server, you can configure redirects, rewrites, and custom headers declaratively in next.config.js
.
Example:
// next.config.js
module.exports = {
async redirects() {
return [
{
source: '/old-blog/:slug',
destination: '/blog/:slug',
permanent: true,
},
];
},
async rewrites() {
return [
{ source: '/api/:path*', destination: 'https://api.external.com/:path*' },
];
},
async headers() {
return [
{
source: '/(.*)',
headers: [{ key: 'X-Frame-Options', value: 'DENY' }],
},
];
},
};
Docs: https://nextjs.org/docs/api-reference/next.config.js/redirects
Tip: Rewrites are great for proxying APIs during SSR without exposing client-side API keys, and headers are handy to set security policies at the edge.
Quick checklist to get started using these features
- Audit pages that unintentionally use server-only APIs and recover automatic static optimization where needed.
- Add
revalidate
to selected static pages and create protected revalidation endpoints for CMS webhooks. - Replace raw script tags with
next/script
and mark LCP images withpriority
innext/image
. - Move small auth/redirect logic to Middleware for lower-latency checks.
- Explore route handlers when migrating to the App Router and use
runtime = 'edge'
for CDN execution. - Use
next/font
for consistent, optimized fonts and to avoid FOIT/CLS. - Configure redirects/rewrites/headers in
next.config.js
to simplify deployment rules.
Further reading
- Next.js Docs - main site: https://nextjs.org/docs
- ISR & Revalidation: https://nextjs.org/docs/basic-features/data-fetching#incremental-static-regeneration
- Middleware: https://nextjs.org/docs/advanced-features/middleware
- next/image: https://nextjs.org/docs/basic-features/image-optimization
- next/script: https://nextjs.org/docs/basic-features/script
- next/font: https://nextjs.org/docs/basic-features/font-optimization
- Route Handlers & App Router: https://nextjs.org/docs/app/building-your-application/routing
These hidden features can dramatically improve performance, developer experience and infrastructure simplicity. Try a couple on a small page and measure impact - next-level wins often come from composing a few of these capabilities together.