Getting Started

Build Your First Next.js App with the App Router

Build a small Next.js App Router app with a home page, dashboard route, and nested layout, starting from create-next-app.

Editorial illustration for Build Your First Next.js App with the App Router

A folder and a page.tsx file are enough to give this small app its second URL. You’ll start with a public home page at /, add /dashboard, then put a layout around the dashboard page. This walkthrough uses the App Router throughout: its routes live under app/. Keeping to one router avoids mixing these file conventions with Pages Router examples.

Set up the project

You’ll need basic React and JavaScript knowledge, Node.js 20.9 or later, and a package manager. The official dashboard course recommends pnpm. From the directory where you keep projects, start a new app with create-next-app:

pnpm create next-app

Choose a project name, TypeScript, and the App Router when prompted. This command uses no --example flag: the course uses that flag to obtain its larger starter project, while here you’re making a minimal app yourself. Change into the project directory after creation. Check package.json for the installed Next.js version rather than assuming a particular version from this walkthrough.

The files you’ll work with will look like this after you add the dashboard files below. app/lib/ is a possible home for helpers, not a folder you need to create for this exercise.

my-app/
├── app/
│   ├── layout.tsx                 # existing root layout; keep it
│   ├── page.tsx                   # /
│   ├── dashboard/
│   │   ├── page.tsx               # /dashboard
│   │   └── layout.tsx             # dashboard UI
│   ├── ui/
│   │   └── dashboard-nav.tsx      # component you will add
│   └── lib/                       # optional future helpers
├── public/                        # static assets
├── next.config.ts                 # if generated with this name
├── tsconfig.json
└── package.json

The course’s project-structure explanation puts routes and application code in app/, UI components in app/ui/, helpers in app/lib/, and static assets in public/. Your newly generated tree need not contain its optional folders. These examples use .tsx because you selected TypeScript; you don’t need advanced TypeScript knowledge to follow them. Keep the generated app/layout.tsx: the root layout supplies the document’s html and body structure.

Write the home page

Replace app/page.tsx with a small page you can recognize in the browser:

export default function HomePage() {
  return (
    <main>
      <h1>Welcome home</h1>
      <p>This is the public home page.</p>
    </main>
  );
}

In the App Router, folders represent URL segments, and the specially named page.tsx makes a route accessible. That is why app/page.tsx serves /. A component file sitting elsewhere under app/ does not, merely by existing, create another page. The layouts and pages lesson also notes that this convention lets you keep UI components, tests, and helpers alongside routes without making those files pages.

Add /dashboard

Create app/dashboard/page.tsx:

export default function DashboardPage() {
  return (
    <main>
      <h1>Dashboard</h1>
      <p>Your dashboard starts here.</p>
    </main>
  );
}

Here, dashboard supplies the URL segment and its page.tsx supplies the page. Together they make /dashboard accessible. There is no database, login, or protected content in this example; “dashboard” is simply the route name.

Give dashboard pages shared UI

First create app/ui/dashboard-nav.tsx:

export default function DashboardNav() {
  return (
    <nav aria-label="Dashboard">
      <a href="/dashboard">Dashboard home</a>
    </nav>
  );
}

Then create app/dashboard/layout.tsx:

import type { ReactNode } from 'react';
import DashboardNav from '../ui/dashboard-nav';

export default function DashboardLayout({
  children,
}: {
  children: ReactNode;
}) {
  return (
    <div>
      <DashboardNav />
      {/* children can be a page or another layout. */}
      {children}
    </div>
  );
}

A layout.tsx supplies shared UI for pages beneath its segment. The dashboard page becomes this layout’s children automatically; if you later nest another layout beneath dashboard, that layout can occupy the same position. The navigation component is imported into the layout, not given its own URL. The generated root layout still surrounds the app; this new layout adds a dashboard-specific layer inside it.

Check the two URLs

Look in package.json for the project’s development script and run it from the project directory—for example, use pnpm dev if the script is named dev. Once the development server starts, visit / and /dashboard at the local address it prints. The first URL should show Welcome home. The second should show Dashboard together with the Dashboard home navigation. Seeing both on /dashboard is the useful check: the page is rendering inside the dashboard layout.

You can now explain the routing rule in one sentence: a folder contributes a URL segment, and a page.tsx inside it makes that URL accessible.

For a larger next step, the official dashboard course extends this foundation into data fetching, invoice mutations, and authentication. Its later work involves a Postgres database and requires GitHub and Vercel accounts; none of those are needed for the two-page app here.

Find a note

Search by topic, title, or keyword.