To create a page, add a page.tsx file inside the app directory and export a React component:
// app/page.tsx
export default function Page() {
return <h1>Hello Next.js!</h1>
}Layouts are shared UI wrappers that persist across navigation. The root layout must include <html> and <body> tags:
// app/layout.tsx
export default function DashboardLayout({ children }) {
return (
<html lang="en">
<body>
<main>{children}</main>
</body>
</html>
);
}To create a route like /blog, add a blog folder inside app and include a page.tsx file:
// app/blog/page.tsx
export default async function Page() {
const posts = await getPosts();
return (
<ul>
{posts.map((post) => (
<Post key={post.id} post={post} />
))}
</ul>
);
}To create a dynamic route like /blog/[slug], wrap the folder name in square brackets:
// app/blog/[slug]/page.tsx
export default async function BlogPostPage({ params }) {
const { slug } = await params;
const post = await getPost(slug);
return (
<div>
<h1>{post.title}</h1>
<p>{post.content}</p>
</div>
);
}Layouts can be nested by adding a layout.tsx file inside route segments. For example, for /blog:
// app/blog/layout.tsx
export default function BlogLayout({ children }) {
return <section>{children}</section>;
}The root layout wraps the blog layout, which wraps the blog page and blog post page.
In server components, use the searchParams prop to access query parameters:
// app/page.tsx
export default async function Page({ searchParams }) {
const filters = (await searchParams).filters;
}In client components, use the useSearchParams hook.
Use the built-in <Link> component from next/link to navigate between routes:
// app/ui/post.tsx
import Link from 'next/link';
export default async function Post({ post }) {
const posts = await getPosts();
return (
<ul>
{posts.map((post) => (
<li key={post.slug}>
<Link href={`/blog/${post.slug}`}>{post.title}</Link>
</li>
))}
</ul>
);
}Next.js generates global helper types for route props:
// app/blog/[slug]/page.tsx
export default async function Page(props: PageProps<'/blog/[slug]'>) {
const { slug } = await props.params;
return <h1>Blog post: {slug}</h1>;
}
// app/dashboard/layout.tsx
export default function Layout(props: LayoutProps<'/dashboard'>) {
return (
<section>
{props.children}
{/* If you have app/dashboard/@analytics */}
{/* {props.analytics} */}
</section>
);
}With page.tsx and layout.tsx files, you can build dynamic, nested, and linkable routes in Next.js. These conventions make your application more flexible, readable, and maintainable.