Return true 404s with notFound()
A route that renders an empty template with status 200 is a soft 404: crawlers index it and users see nothing. Call notFound() when a record is missing or the slug is invalid, add app/not-found.tsx for the layout, and confirm the response status over HTTP. Keep redirects for moved content and reserve notFound() for genuinely absent pages.
Why this matters
Call notFound() instead of rendering an empty page with status 200.
Before you start
- Next.js project with dynamic routes that can receive unknown ids
- A not-found page that matches the site layout
How to apply it
Find the soft-404 routes
Look for dynamic routes that render a shell when the record query returns nothing, and check the HTTP status of a deliberately invalid slug.
Check: curl -sI your production domain/<dynamic-route>/does-not-exist returns 200 before the fix.
Call notFound() on missing data
Import notFound from next/navigation and call it when the record is absent or invalid, before rendering any content.
Check: The same invalid slug now returns 404 after rebuilding.
Add or fix app/not-found.tsx
Create a not-found page with a short explanation, a link home and navigation, and no indexable content that competes with real pages.
Check: The 404 response renders the not-found layout with a link home.
Keep redirects for moved content
Move slugs that changed to redirect rules and leave notFound() for genuinely absent records. Re-check Search Console for soft 404 reports after deploy.
Check: A moved slug redirects to its new URL, while an unknown slug returns 404.
Source: seo-mcp playbook · curated entry · report an error
Framework notes
nextjs-app
Call `notFound()` from `page.tsx` when data is missing and add `app/not-found.tsx`; Next.js renders it with a real 404 status.
nextjs-pages
Return `{ notFound: true }` from `getServerSideProps` or `getStaticProps` and keep `pages/404.tsx` as the fallback layout.