Course page
Log in

You are watching a free preview. Enroll to open all 25 lessons, track progress and ask the course tutor.

Enroll for $79.99

Section 1: Foundations of the App Router

Creating the project

Article 10 min Lesson 2 of 25 Preview

Create a new app with the official starter:

npx create-next-app@latest shelf

Accept TypeScript, ESLint, Tailwind CSS, the src directory and the App Router. Turbopack is the default bundler for development and builds in current versions, so you do not need to opt in. Then start the dev server:

cd shelf
npm run dev

The generated structure

src/app/
  layout.tsx    root layout with <html> and <body>
  page.tsx      the home page at /
  globals.css
public/         static files served as is
next.config.ts

The root layout is required. It is the only place where you render <html> and <body>, and it is a good place for fonts and global providers. Next.js includes next/font, which downloads fonts at build time and serves them from your own domain, avoiding layout shift and third party requests.

Environment variables

Create a .env.local file for secrets such as the database URL. Variables are available on the server through process.env. Only variables prefixed with NEXT_PUBLIC_ are inlined into client bundles, so never give a secret that prefix. Add .env.local to .gitignore (the starter does this already) and keep a .env.example file with empty values for teammates.

A first route

Create src/app/books/page.tsx:

export default async function BooksPage() {
  const books = [{ id: 1, title: "Example" }];
  return (
    <main>
      <h1>My books</h1>
      <ul>{books.map((b) => <li key={b.id}>{b.title}</li>)}</ul>
    </main>
  );
}

Notice the component is async. Server components can await data directly, which is something client components cannot do. Visit /books and view the page source: the list is already in the HTML.

Commit this. Next we look at how routes, layouts and navigation fit together.

← → switch lessons