File Conventions: loading, not-found, template, default, route
Special files next to page.tsx add UX without wiring everything by hand. loading.tsx shows an instant fallback while Server Components load (Suspense boundary). not-found.tsx renders when notFound() is called or no route matches. error.tsx catches errors in that segment (must be a Client Component).
loading, not-found, and error files
Special files next to page.tsx add UX without wiring everything by hand. loading.tsx shows an instant fallback while Server Components load (Suspense boundary). not-found.tsx renders when notFound() is called or no route matches. error.tsx catches errors in that segment (must be a Client Component).
Real-life example: loading is the "please wait" screen at a ticket window. not-found is "counter closed". error is "system down — try again" with a reset button.
export default function Loading() {
return <p>Loading Rishtaara courses…</p>;
}import Link from "next/link";
export default function NotFound() {
return (
<div>
<h1>Course not found</h1>
<Link href="/courses">Back to courses</Link>
</div>
);
}"use client";
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
return (
<div>
<h2>Something went wrong</h2>
<p>{error.message}</p>
<button type="button" onClick={() => reset()}>
Try again
</button>
</div>
);
}template.tsx vs layout.tsx
layout.tsx persists across navigations inside its segment — state and DOM can be reused. template.tsx creates a new instance for each navigation — useful for enter animations or resetting client state per page visit.
Most apps need layout. Reach for template when you explicitly want a fresh mount every time.
Real-life example: Layout is your desk that stays messy between meetings. Template is a cleaned whiteboard brought in for every new meeting.
import type { ReactNode } from "react";
export default function DashboardTemplate({
children,
}: {
children: ReactNode;
}) {
// Remounts on each dashboard page navigation
return <div className="page-enter">{children}</div>;
}default.js and route.js — previews
Parallel routes use named slots like @analytics beside page.tsx. default.tsx (or default.js) is the fallback when Next.js cannot recover a slot on soft navigation — you will use it when you build multi-slot dashboards.
route.ts (or route.js) defines a Route Handler — an API endpoint at that path (GET, POST, …). Full API patterns come in a later lesson; for now know it lives next to pages as a file convention.
Real-life example: default.js is a spare tire for a dashboard panel. route.js is a service window that speaks JSON instead of HTML.
app/dashboard/
layout.tsx
page.tsx
@analytics/
page.tsx
default.tsx # fallback for @analytics slot
@team/
page.tsx
default.tsximport { NextResponse } from "next/server";
export async function GET() {
return NextResponse.json({
message: "Hello from Rishtaara API",
});
}
// POST, PUT, DELETE work the same way — export named functions.
// Details in the Route Handlers lesson later.Metadata files — brief tour
App Router also supports special metadata files: favicon.ico, icon.png, apple-icon.png, opengraph-image.tsx, twitter-image.tsx, robots.txt, sitemap.ts. Place them in app/ (or a route segment) and Next.js wires them into <head> or well-known URLs.
You can also export a metadata object or generateMetadata function from layout.tsx / page.tsx for titles and descriptions — you already saw a small example in the root layout lesson.
Real-life example: Metadata files are the shop sign, logo sticker, and visiting card — people see them before they read the menu (page body).
- favicon.ico / icon — browser tab icon
- opengraph-image — social share preview
- sitemap.ts / robots.txt — SEO crawlers
- metadata export — title, description, Open Graph fields