SyntaxStudy
Sign Up
Next.js Creating Pages with page.tsx
Next.js Beginner 1 min read

Creating Pages with page.tsx

In the App Router, a page is a React component exported as the default export from a page.tsx file. The component can be async — this is the primary way to fetch data in server components. Because page.tsx files are server components by default, they run only on the server and their code is never sent to the browser, which keeps the client bundle small and allows direct access to databases, file systems, and environment variables. Pages receive two props: params (an object containing dynamic route segment values) and searchParams (an object containing the current URL query string parameters). Unlike params, searchParams is not available in layouts — only pages get searchParams because layouts are cached and shared across navigations while searchParams changes on every request. Each page can export several optional configuration constants that control how Next.js renders and caches it. The dynamic export can be set to 'force-dynamic' to opt the page out of caching, 'force-static' to force static generation, or 'auto' (the default). The revalidate export sets the ISR revalidation interval in seconds. The runtime export can switch the page to the Edge Runtime for lower latency.
Example
// app/products/[id]/page.tsx

import { notFound } from 'next/navigation';
import type { Metadata } from 'next';

interface Props {
  params: { id: string };
  searchParams: { color?: string; size?: string };
}

// Static metadata
// (see generateMetadata for dynamic metadata)
export const metadata: Metadata = {
  title: 'Product Detail',
};

// Opt this page into dynamic rendering (no caching)
export const dynamic = 'force-dynamic';

async function getProduct(id: string) {
  const res = await fetch(`https://api.example.com/products/${id}`);
  if (!res.ok) return null;
  return res.json();
}

export default async function ProductPage({ params, searchParams }: Props) {
  const product = await getProduct(params.id);

  if (!product) notFound();

  const { color = 'default', size = 'M' } = searchParams;

  return (
    <section>
      <h1>{product.name}</h1>
      <p>Selected colour: {color}</p>
      <p>Selected size: {size}</p>
      <p className="text-2xl font-bold">${product.price}</p>
    </section>
  );
}