~3 min read • Updated Oct 29, 2025
1. loading.js — Instant Loading UI with Suspense
The loading.js file lets you show a fallback UI instantly while a route segment streams in. It wraps page.js and its children in a <Suspense> boundary.
// app/feed/loading.tsx
export default function Loading() {
return <p>Loading...</p>
}Best Practices:
- Use lightweight UI like skeletons or spinners
- Can be a Server or Client Component
- Prefetched for fast navigation
- Shared layouts stay interactive during loading
Manual Suspense Boundaries:
// app/dashboard/page.tsx
import { Suspense } from 'react'
import { PostFeed, Weather } from './Components'
export default function Posts() {
return (
<section>
<Suspense fallback={<p>Loading feed...</p>}>
<PostFeed />
</Suspense>
<Suspense fallback={<p>Loading weather...</p>}>
<Weather />
</Suspense>
</section>
)
}2. SEO and Streaming Behavior
- Metadata: Resolved before streaming begins
- Status Code: Always 200 for streamed content
- Soft 404s: Prevented using
<meta name="robots" content="noindex">
3. not-found.js — Route-Level 404 UI
Use not-found.js to display a custom 404 when notFound() is called inside a route segment.
// app/not-found.tsx
import Link from 'next/link'
export default function NotFound() {
return (
<div>
<h2>Not Found</h2>
<p>Could not find requested resource</p>
<Link href="/">Return Home</Link>
</div>
)
}Streaming vs Non-Streaming:
- Streamed: status 200 +
noindexmeta tag - Non-streamed: status 404
Async NotFound Example:
export default async function NotFound() {
const headersList = await headers()
const domain = headersList.get('host')
const data = await getSiteData(domain)
return (
<div>
<h2>Not Found: {data.name}</h2>
<p>Could not find requested resource</p>
<p><Link href="/blog">View all posts</Link></p>
</div>
)
}4. global-not-found.js — App-Wide 404 Page
Use global-not-found.js to define a fallback 404 page for unmatched routes across your app.
// app/global-not-found.tsx
import './globals.css'
import { Inter } from 'next/font/google'
const inter = Inter({ subsets: ['latin'] })
export default function GlobalNotFound() {
return (
<html lang="en" className={inter.className}>
<body>
<h1>404 - Page Not Found</h1>
<p>This page does not exist.</p>
</body>
</html>
)
}Enable in next.config.ts:
const nextConfig = {
experimental: {
globalNotFound: true,
},
}Use Cases:
- Multiple root layouts (e.g.
(admin),(shop)) - Top-level dynamic segments (e.g.
[country])
Conclusion
With loading.js, not-found.js, and global-not-found.js, Next.js gives you full control over streaming UI and graceful error handling. These features improve user experience, navigation speed, and SEO — making your app feel fast, responsive, and reliable.
Written & researched by Dr. Shahin Siami