~2 min read • Updated Nov 1, 2025
1. Access Control with unauthorized()
unauthorized() throws a 401 error and renders the unauthorized.tsx page. It’s ideal for protecting sensitive routes and redirecting unauthenticated users to a login UI.
Enable in next.config.js:
experimental: {
authInterrupts: true,
}Example in Server Component:
const session = await verifySession()
if (!session) unauthorized()Custom UI:
// app/unauthorized.tsx
<main>
<h1>401 - Unauthorized</h1>
<p>Please log in to access this page.</p>
<Login />
</main>2. Smart Caching with unstable_cache()
unstable_cache() memoizes expensive operations like database queries across requests and deployments.
Example:
const getCachedUser = unstable_cache(
async (id) => fetchUser(id),
['user-cache-key'],
{ tags: ['users'], revalidate: 60 }
)Tips:
- Avoid accessing cookies or headers inside cached functions
- Use tags for targeted invalidation
- Use revalidate to set cache duration
3. Real-Time Invalidation with updateTag()
updateTag() expires cached data instantly after a mutation. It’s only available in Server Actions.
Example:
'use server'
import { updateTag } from 'next/cache'
export async function createPost(formData) {
const post = await db.post.create({ data: formData })
updateTag('posts')
updateTag(`post-${post.id}`)
redirect(`/posts/${post.id}`)
}4. Opting Out of Caching with unstable_noStore()
unstable_noStore() disables caching and forces dynamic rendering.
Example:
import { unstable_noStore as noStore } from 'next/cache'
export default async function Component() {
noStore()
const data = await db.query(...)
}5. Preserving Error Behavior with unstable_rethrow()
Use unstable_rethrow() to preserve Next.js error handling when catching errors like notFound() or redirect().
Example:
try {
const res = await fetch(...)
if (res.status === 404) notFound()
} catch (err) {
unstable_rethrow(err)
}6. Navigation Feedback with useLinkStatus()
useLinkStatus() tracks the pending state of a <Link> for subtle UI feedback during navigation.
Example:
'use client'
import { useLinkStatus } from 'next/link'
function Hint() {
const { pending } = useLinkStatus()
return <span className={`link-hint ${pending ? 'is-pending' : ''}`} />
}Best Practices:
- Use with
prefetch={false} - Avoid layout shifts by animating opacity
- Use route-level fallbacks with
loading.js
Conclusion
With unauthorized() for access control, unstable_cache() for smart caching, updateTag() for real-time invalidation, and useLinkStatus() for smooth navigation, you can build secure, performant, and dynamic applications in Next.js.
Written & researched by Dr. Shahin Siami