How to Create Pages in Nextjs

How to Create Pages in Next.js Next.js has rapidly become the go-to framework for building modern, high-performance web applications in React. Its intuitive file-based routing system, server-side rendering (SSR), static site generation (SSG), and built-in optimization features make it ideal for everything from simple blogs to enterprise-scale applications. At the heart of Next.js is its powerful p

Nov 10, 2025 - 08:37
Nov 10, 2025 - 08:37
 2

How to Create Pages in Next.js

Next.js has rapidly become the go-to framework for building modern, high-performance web applications in React. Its intuitive file-based routing system, server-side rendering (SSR), static site generation (SSG), and built-in optimization features make it ideal for everything from simple blogs to enterprise-scale applications. At the heart of Next.js is its powerful page creation system a clean, convention-driven approach that eliminates the need for complex routing configurations. In this comprehensive guide, youll learn exactly how to create pages in Next.js, from the most basic setup to advanced patterns that scale with your application. Whether youre new to Next.js or looking to refine your workflow, this tutorial will equip you with the knowledge to build fast, SEO-friendly, and maintainable applications with confidence.

Step-by-Step Guide

Setting Up a Next.js Project

Before you can create pages, you need a working Next.js project. The fastest way to get started is by using the official create-next-app CLI tool. Open your terminal and run the following command:

npx create-next-app@latest my-next-app

The CLI will prompt you with a series of options. For a standard setup, accept the defaults: choose TypeScript if you prefer type safety, ESLint for code quality, and Tailwind CSS if you want a pre-configured styling framework. When prompted to use the App Router, select Yes this is the modern, recommended approach in Next.js 13+.

Once the installation completes, navigate into your project folder:

cd my-next-app

Start the development server:

npm run dev

Open http://localhost:3000 in your browser. Youll see the default Next.js welcome page. This confirms your project is running successfully.

Understanding the App Router Structure

Next.js 13 introduced the App Router, which replaced the older Pages Router. The App Router organizes pages using a hierarchical folder structure inside the app directory. This structure is more flexible and enables advanced features like nested layouts, server components, and streaming.

By default, your app folder contains a page.tsx (or page.js) file. This file represents the root route of your application /. When a user visits your sites homepage, Next.js renders the content of this file.

To create additional pages, simply add new folders inside the app directory and include a page.tsx file in each. For example:

  • app/page.tsx ? /
  • app/about/page.tsx ? /about
  • app/blog/page.tsx ? /blog
  • app/contact/page.tsx ? /contact

Each page.tsx file is a React component that returns JSX. Heres an example of a simple About page:

// app/about/page.tsx

export default function AboutPage() {

return (

<div>

<h1>About Us</h1>

<p>We are a team of developers building the future of the web.</p>

</div>

);

}

After saving this file, refresh your browser and navigate to /about. Youll immediately see your new page rendered without any additional configuration.

Creating Dynamic Pages with Square Brackets

One of Next.jss most powerful features is its ability to generate dynamic routes using square brackets. This is essential for content-heavy sites like blogs, e-commerce platforms, or user profiles.

To create a dynamic page, wrap the dynamic segment in square brackets. For example, to create a blog post page that accepts a dynamic slug:

  1. Create a folder named app/blog/[slug].
  2. Inside that folder, create a page.tsx file.

Now, your route will match any value after /blog/. For example:

  • /blog/my-first-post
  • /blog/nextjs-tutorial
  • /blog/seo-best-practices

In your page.tsx, you can access the dynamic segment using the params prop:

// app/blog/[slug]/page.tsx

export default function BlogPost({ params }: { params: { slug: string } }) {

return (

<div>

<h1>Blog Post: {params.slug}</h1>

<p>This is the content for the post titled "{params.slug}"</p>

</div>

);

}

For production use, youll typically fetch data based on the slug. Next.js provides the generateStaticParams function for static generation and generateMetadata for SEO optimization.

Using generateStaticParams for Static Generation

If youre using static site generation (SSG), you need to tell Next.js which dynamic routes to pre-render at build time. This is done using the generateStaticParams function.

Lets say you have a list of blog posts stored in a JSON file or fetched from a CMS. Heres how youd implement it:

// app/blog/[slug]/page.tsx

import { getBlogPosts } from '@/lib/data';

export default function BlogPost({ params }: { params: { slug: string } }) {

const post = getBlogPosts().find(p => p.slug === params.slug);

if (!post) {

return <h1>Post not found</h1>;

}

return (

<div>

<h1>{post.title}</h1>

<time>{post.date}</time>

<div dangerouslySetInnerHTML={{ __html: post.content }} />

</div>

);

}

export async function generateStaticParams() {

const posts = getBlogPosts();

return posts.map(post => ({

slug: post.slug,

}));

}

When you run npm run build, Next.js will automatically generate HTML files for each blog post listed in your data source. This ensures lightning-fast load times and excellent SEO performance.

Creating Nested Routes

Next.js supports nested routing, allowing you to build complex UIs with shared layouts. For example, you might want a blog section with subpages like /blog/categories and /blog/authors.

To achieve this, create nested folders:

  • app/blog/page.tsx ? /blog
  • app/blog/categories/page.tsx ? /blog/categories
  • app/blog/authors/page.tsx ? /blog/authors

You can also create a layout that wraps all blog pages. Create a layout.tsx file inside the app/blog folder:

// app/blog/layout.tsx

export default function BlogLayout({

children,

}: {

children: React.ReactNode;

}) {

return (

<div>

<nav>

<ul>

<li><a href="/blog">All Posts</a></li>

<li><a href="/blog/categories">Categories</a></li>

<li><a href="/blog/authors">Authors</a></li>

</ul>

</nav>

<main>

{children}

</main>

</div>

);

}

Now, every page inside the blog directory will automatically include this navigation bar. This reduces code duplication and improves maintainability.

Handling 404 Pages

Next.js automatically renders a built-in 404 page when a route doesnt exist. However, you can customize it by creating a not-found.tsx file in your app directory.

// app/not-found.tsx

export default function NotFound() {

return (

<div style={{ padding: '4rem', textAlign: 'center' }}>

<h1>404 Page Not Found</h1>

<p>The page youre looking for doesnt exist.</p>

<a href="/">Go Home</a>

</div>

);

}

This file will be displayed whenever a user visits a route that doesnt match any page in your app. Its a simple but essential part of user experience.

Using Server Components for Better Performance

By default, all components in the App Router are Server Components. This means they execute on the server, reducing client-side JavaScript and improving performance and SEO.

You dont need to do anything special just write your components normally. For example:

// app/dashboard/page.tsx

import { getDashboardData } from '@/lib/api';

export default function Dashboard() {

const data = getDashboardData(); // This runs on the server

return (

<div>

<h1>Your Dashboard</h1>

<p>Welcome back, {data.user.name}</p>

<ul>

{data.items.map(item => (

<li key={item.id}>{item.name}</li>

))}

</ul>

</div>

);

}

Server Components are ideal for fetching data, reading files, or interacting with databases. They eliminate the need for client-side data fetching in many cases, resulting in faster initial loads.

Client Components When Needed

Some interactions like handling form submissions, animations, or user input require client-side JavaScript. To mark a component as a Client Component, add the use client directive at the top of the file:

'use client';

import { useState } from 'react';

export default function Counter() {

const [count, setCount] = useState(0);

return (

<div>

<p>Count: {count}</p>

<button onClick={() => setCount(count + 1)}>Increment</button>

</div>

);

}

Use Client Components sparingly only when you need interactivity. Overusing them can increase bundle size and hurt performance.

Best Practices

Use Meaningful File and Folder Names

Consistency in naming improves readability and collaboration. Use lowercase, hyphen-separated names for routes: /contact-us instead of /ContactUs. Avoid special characters, spaces, or uppercase letters in folder names.

Organize by Feature, Not Type

Instead of grouping files by type (e.g., all components in one folder, all pages in another), group them by feature or module. For example:

  • app/user/profile/page.tsx
  • app/user/settings/page.tsx
  • app/user/settings/layout.tsx

This structure makes it easier to locate and maintain related code as your project grows.

Always Use generateMetadata for SEO

Next.js provides the generateMetadata function to dynamically set page titles, descriptions, Open Graph tags, and more. This is critical for search engine visibility and social sharing.

// app/blog/[slug]/page.tsx

import { getBlogPost } from '@/lib/data';

export default function BlogPost({ params }: { params: { slug: string } }) {

const post = getBlogPost(params.slug);

if (!post) return <h1>Not Found</h1>;

return (

<div>

<h1>{post.title}</h1>

<article>{post.content}</article>

</div>

);

}

export async function generateMetadata({

params,

}: {

params: { slug: string };

}) {

const post = getBlogPost(params.slug);

return {

title: post.title,

description: post.excerpt,

openGraph: {

title: post.title,

description: post.excerpt,

images: [post.image],

},

};

}

Never rely on default metadata. Always define it explicitly to ensure consistent SEO performance across all pages.

Prefer Static Generation Over Server-Side Rendering

While Next.js supports both SSR and SSG, SSG is generally preferred for public-facing content. Pages generated at build time are cached by CDNs and delivered instantly to users worldwide. SSR is useful for highly personalized or frequently changing content (like dashboards), but it adds latency.

Use generateStaticParams and revalidate (for ISR) to balance freshness and performance.

Optimize Images and Assets

Next.js includes a built-in Image component that automatically optimizes images. Always use next/image instead of standard <img> tags:

import Image from 'next/image';

export default function HomePage() {

return (

<div>

<Image

src="/hero-image.jpg"

alt="Hero banner"

width={1200}

height={600}

priority

/>

</div>

);

}

The Image component automatically converts images to WebP, serves responsive sizes, and lazy-loads offscreen images. This can drastically improve Lighthouse scores.

Implement Proper Navigation

Use next/link for client-side navigation between pages. Avoid using standard anchor tags (<a>) unless linking to external sites.

import Link from 'next/link';

export default function Navbar() {

return (

<nav>

<ul>

<li><Link href="/">Home</Link></li>

<li><Link href="/about">About</Link></li>

<li><Link href="/blog">Blog</Link></li>

</ul>

</nav>

);

}

This enables SPA-like navigation with faster transitions and preserved state.

Test Your Pages Across Devices and Networks

Use Chrome DevTools to simulate mobile devices and slow 3G connections. Test your pages with Lighthouse to identify performance bottlenecks. Aim for scores above 90 in performance, accessibility, and SEO.

Version Control and Deployment

Always commit your node_modules folder to .gitignore. Deploy your Next.js app using Vercel (the creators of Next.js), Netlify, or any platform that supports Node.js. Vercel offers automatic preview deployments for every pull request a huge productivity boost for teams.

Tools and Resources

Official Next.js Documentation

The Next.js documentation is comprehensive and regularly updated. It includes guides, API references, and code examples for every feature. Bookmark it as your primary reference.

Next.js Examples Repository

GitHub hosts an official examples repository with dozens of real-world templates from blogs and e-commerce stores to CMS integrations. These are invaluable for learning advanced patterns.

VS Code Extensions

Install these extensions to improve your workflow:

  • ESLint for code quality
  • Prettier for consistent formatting
  • Next.js Snippets for quick code generation
  • Path Intellisense for auto-completing file paths

Content Management Systems (CMS)

Integrate Next.js with headless CMS platforms to manage content dynamically:

  • Sanity flexible, developer-friendly
  • Contentful enterprise-grade
  • Strapi open-source, self-hosted
  • WordPress REST API for migrating existing sites

Use the getStaticProps or generateStaticParams functions to fetch content at build time.

Analytics and Monitoring

Integrate analytics tools like Google Analytics, Plausible, or PostHog to track user behavior. Next.js makes it easy to add tracking scripts via the app/layout.tsx file:

// app/layout.tsx

import Script from 'next/script';

export default function RootLayout({

children,

}: {

children: React.ReactNode;

}) {

return (

<html lang="en">

<head>

<Script strategy="afterInteractive">

{

window.dataLayer = window.dataLayer || [];

function gtag(){dataLayer.push(arguments);}

gtag('js', new Date());

gtag('config', 'G-XXXXXXXXXX');

}

</Script>

</head>

<body>

{children}

</body>

</html>

);

}

Testing Tools

Use Jest and React Testing Library to write unit and integration tests for your pages and components. Test both the UI and data-fetching logic to ensure reliability.

Performance Auditing Tools

  • Lighthouse built into Chrome DevTools
  • Web Vitals measure real user experience
  • Bundlephobia analyze package sizes
  • Next.js Analytics (Vercel) track performance metrics in production

Real Examples

Example 1: Personal Blog with Markdown

Many developers use Next.js to build personal blogs powered by Markdown files. Heres how it works:

  1. Store blog posts as .md files in content/posts/.
  2. Use remark and rehype to convert Markdown to HTML.
  3. Read files using fs (Node.js) in generateStaticParams.
  4. Render posts with dangerouslySetInnerHTML or a Markdown component.

Benefits:

  • No database required
  • Fast, static builds
  • Easy to version control
  • Perfect for SEO

Example 2: E-Commerce Product Pages

For an e-commerce site, you might have:

  • app/products/page.tsx lists all products
  • app/products/[id]/page.tsx individual product detail
  • app/products/category/[slug]/page.tsx filtered by category

Each product page fetches data from an API like Shopify or Medusa. Youd use generateStaticParams to pre-render thousands of product pages at build time. For frequently updated inventory, use Incremental Static Regeneration (ISR) with a revalidate value of 60 seconds:

export async function generateStaticParams() {

const products = await fetch('https://api.example.com/products').then(res => res.json());

return products.map(product => ({ id: product.id }));

}

export default async function ProductPage({ params }: { params: { id: string } }) {

const product = await fetch(https://api.example.com/products/${params.id}).then(res => res.json());

return (

<div>

<h1>{product.name}</h1>

<p>${product.price}</p>

<button>Add to Cart</button>

</div>

);

}

export const revalidate = 60; // Re-generate every minute

Example 3: Multi-Language Site

Next.js supports internationalization (i18n) out of the box. Configure it in next.config.js:

// next.config.js

/** @type {import('next').NextConfig} */

const nextConfig = {

i18n: {

locales: ['en', 'es', 'fr'],

defaultLocale: 'en',

},

};

module.exports = nextConfig;

Then create locale-specific folders:

  • app/en/page.tsx
  • app/es/page.tsx
  • app/fr/page.tsx

Next.js automatically prefixes routes with the locale: /es/about, /fr/contact, etc. You can use next-intl or next-i18next for advanced translation management.

FAQs

Can I use Next.js without TypeScript?

Yes. Next.js fully supports JavaScript. When creating a new project, choose No for TypeScript. However, TypeScript is strongly recommended for larger applications due to improved code reliability and developer experience.

Do I need a server to run Next.js?

No. Next.js apps can be deployed as static sites (SSG) and served from any CDN. You only need a server if youre using Server Components with data fetching that requires backend access (like database queries). Even then, platforms like Vercel handle serverless functions automatically.

How do I add custom fonts in Next.js?

Use the app/layout.tsx file to import fonts. For Google Fonts:

// app/layout.tsx

import { Inter } from 'next/font/google';

const inter = Inter({ subsets: ['latin'] });

export default function RootLayout({

children,

}: {

children: React.ReactNode;

}) {

return (

<html lang="en">

<body className={inter.className}>

{children}

</body>

</html>

);

}

Whats the difference between App Router and Pages Router?

The App Router (introduced in Next.js 13) uses the app directory and supports Server Components, nested layouts, and streaming. The Pages Router (legacy) uses the pages directory and relies on client-side components. New projects should use the App Router. Existing projects can gradually migrate.

Can I use Next.js for mobile apps?

Next.js is designed for web applications. However, you can use frameworks like Expo + Next.js or React Native Web to share code between web and mobile platforms. Next.js itself does not build native mobile apps.

How do I handle authentication in Next.js?

Use NextAuth.js (now Auth.js) the official authentication library for Next.js. It supports OAuth, email/password, and social logins. Store sessions in cookies or JWT, and protect routes using middleware or server components.

Is Next.js good for SEO?

Yes. Next.js excels at SEO due to server-side rendering, static generation, automatic meta tags, and optimized asset loading. Pages are rendered with clean HTML, making them easily crawlable by search engines.

How do I deploy a Next.js app?

The easiest way is to deploy to Vercel simply push your code to GitHub, and Vercel auto-deploys it. You can also deploy to Netlify, AWS Amplify, or any Node.js-compatible host. For static sites, you can even upload the out folder (generated by next export) to any static hosting service.

Conclusion

Creating pages in Next.js is one of the most straightforward and powerful aspects of the framework. With its file-based routing system, you can build complex, scalable applications without writing a single line of routing configuration. From simple static pages to dynamic, data-driven content, Next.js adapts to your needs whether youre building a portfolio, a blog, an e-commerce store, or a full-fledged SaaS product.

By following the best practices outlined in this guide organizing your app structure logically, leveraging static generation, optimizing metadata, and using the right tools youll not only create faster, more reliable websites, but also future-proof your development workflow. The App Router, server components, and built-in performance optimizations make Next.js the most developer-friendly and SEO-optimized framework available today.

Start small, experiment with dynamic routes, integrate a CMS, and gradually add complexity. The more you build, the more youll appreciate Next.jss elegance and power. Whether youre a beginner or an experienced developer, mastering page creation in Next.js is a foundational skill that will elevate your web development career.