cf.completefrontend
Open lab My progress
THE NEXT.JS FIELD GUIDE

Creating a Next.js app

Start a Next.js project with create-next-app: its questions and defaults, the files it writes, and how next dev, next build and next start run it.

By the end, you can
  • 01
    Create a projectRun create-next-app with its questions or with flags, and say what each answer writes into the project.
  • 02
    Run it two waysUse next dev while you work, and next build then next start for the finished app, and read what each one prints.
  • 03
    Know the tools around itSay what Turbopack, ESLint or Biome, and AGENTS.md each do in a new project, and which Node.js it needs.

One command, a whole project

A Next.js app lives in a project: a folder with your pages, a list of the packages they need, and a few settings files. You could write each file by hand. Next.js has a tool that writes them for you, called create-next-app. These three commands make the tea shop's project and start it:

Make the tea shop's project, and start itShell
npx create-next-app@latest tea-shop --yes
cd tea-shop
npm run dev

You type them in a terminal, the window where you run programs by name. Line 1 runs create-next-app with npx, which downloads a package's command and runs it without adding it to your computer for good (npm and packages explains packages). @latest asks for the newest version, which was 16.4.3 on October 29, 2026. tea-shop is the name of the new folder, and --yes skips the questions it would ask. Line 2 moves into the new folder. Line 3 starts the app, so you can open it in the browser.

Here is what line 1 printed when it ran for this lesson. (The folder's path is shortened to ~/projects.)

What create-next-app 16.4.3 printedText
Creating a new Next.js app in ~/projects/tea-shop.

Using npm.

Initializing project with template: app-tw

Installing dependencies:
- next
- react
- react-dom

Installing devDependencies:
- @tailwindcss/turbopack
- @types/node
- @types/react
- @types/react-dom
- eslint
- eslint-config-next
- tailwindcss
- typescript

npm warn deprecated eslint@9.39.5: This version is no longer supported. Please see https://eslint.org/version-support for other options.

added 364 packages, and audited 365 packages in 23s

146 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

Generating route types...
✓ Types generated successfully

Initialized a git repository.

Success! Created tea-shop at ~/projects/tea-shop

Read it from the top:

  • Line 1 makes the folder. Line 3 says it uses npm, because npx is npm's.
  • Line 5 names the template it copies: app-tw, a starter app for the App Router with Tailwind CSS.
  • Lines 7 to 20 list the packages it installs. dependencies are what the app needs to run: Next.js and React. devDependencies are tools you only need while you work on it, like TypeScript.
  • Line 22 is npm warning that this ESLint version is old. It's only a warning: nothing stops. Lines 24 to 29 are npm's usual report.
  • Lines 31 and 32 write route types: TypeScript types for your pages and their addresses, like the LayoutProps you'll meet below. Line 34 starts a git repository, so you can save versions of your work. Line 36 says it's done.
A terminal window with the command npx create-next-app at latest, tea-shop, dash dash yes. An arrow goes to a folder window named tea-shop that holds app, public, package.json, next.config.ts, tsconfig.json, eslint.config.mjs and AGENTS.md, with packages installed.terminalnpx create-next-apptea-shop --yesone commandtea-shopapp/public/package.jsonnext.config.tstsconfig.jsoneslint.config.mjsAGENTS.md
One command writes the whole project into a new folder, tea-shop, and installs its packages. These are the files and folders at its top level, apart from README.md, .gitignore and next-env.d.ts.

You can also ask for less. With --empty, the app has one page that says Hello world!, and --no-tailwind --no-linter leaves out Tailwind CSS and the linter. That small project is where every recorded example in this course starts. Here it is, built with next build and run with next start, and recorded. Click a file in the tree to read it.

The project create-next-app --empty --no-tailwind --no-linter makesNext.js
app/
app/page.tsx
export default function Home() {  return (    <main>      <div>Hello world!</div>    </main>  );}
Recorded from Next.js 16.4.3
localhost:3000/Create Next App
Hello world!

The page as the browser shows it when its HTML arrives, drawn with plain styles. Its JavaScript doesn't run here.

app/page.tsx is the home page. Its component, Home, returns a <main> with Hello world! in it, and the Browser tab shows exactly that. app/layout.tsx is the root layout: on lines 10 and 11, it gives every page its <html> and <body>, and lines 3 to 6 give every page the title Create Next App, which shows in the browser frame. The files marked create-next-app are its settings: package.json, tsconfig.json and next.config.ts. They're the same in every recorded example of the course.

Real-life analogyA kitchen fitted for you

You could build a kitchen yourself: buy each cupboard, plumb the sink, wire the oven. Or a fitter asks you a few questions and puts a working kitchen in, with everything where cooks expect it. You still decide what to cook. You try recipes for yourself first, and before the restaurant opens, you cook the whole menu once to be sure it all works.

In real life: The fitter asks a few questions: gas or electric, which worktop
In Next.js: create-next-app asks: TypeScript, which linter, Tailwind CSS
In real life: Cupboards, sink and oven in the usual places
In Next.js: app, public and the settings files where Next.js expects them
In real life: Cooking for yourself while you try recipes
In Next.js: npm run dev, while you write the app
In real life: The full menu cooked before the restaurant opens
In Next.js: npm run build, then npm run start to serve it
In real life: The manual in the drawer, for anyone new who cooks there
In Next.js: AGENTS.md, which points coding agents at the docs
The main idea

create-next-app writes a working Next.js project from your answers, and installs its packages. Then three scripts run it: npm run dev while you work, and npm run build followed by npm run start for the finished app.

What your computer needs first

create-next-app, next dev, next build and next start are programs that run on Node.js, the program that runs JavaScript outside the browser. Next.js 16.4.3 needs Node.js 20.9.0 or newer: its package.json says "node": ">=20.9.0", and create-next-app's says the same. Next.js 16 raised the minimum from Node.js 18. To see your version, run:

Which Node.js do you have?Shell
node -v

On the computer this lesson's runs were made on, it printed v22.23.3: version 22, newer than 20.9, so it's fine. If yours prints a lower number, install the current long-term support version from nodejs.org first. Each row is one thing you need:

What a new Next.js project needs
What you needWhich versionHow to check
Node.js20.9 or newer. Next.js 16 stopped supporting Node.js 18.Run node -v in a terminal.
A package managernpm comes with Node.js. pnpm, Yarn and Bun work too.create-next-app prints Using npm. (or the one you used).
TypeScript5.1 or newer. You don't install it yourself: the project lists it, and npm installs the newest 5.x.Look for typescript in devDependencies.
An operating systemmacOS, Windows (including WSL) or Linux.Any computer that runs Node.js 20.9.

TypeScript 5.1 is the oldest TypeScript Next.js 16 works with. You don't install it yourself: the project lists "typescript": "^5" (the ^ means any version 5.x), and npm installs the newest 5.x (5.9.3 for this lesson's project). If you prefer another package manager, start the command with it, like pnpm create next-app, or add --use-pnpm, --use-yarn or --use-bun. If TypeScript is new to you, the code in this course stays simple: mostly the same JavaScript, with a type here and there.

The questions create-next-app asks

Without --yes, and without any other option, create-next-app asks questions. This is the start of a run of npx create-next-app@latest, typed in a terminal:

The first two questionsText
✔ What is your project named? … tea-shop
? Would you like to use the recommended Next.js defaults? › - Use arrow-keys. Return to submit.
❯   Yes, use recommended defaults
    TypeScript, ESLint, No React Compiler, Tailwind CSS, No src/ directory, App Router, Cache Components, AGENTS.md, Agent feedback
    No, customize settings

Line 1 asked for the project's name, and tea-shop was typed. Line 2 asks the main question, and the arrow keys move between its answers. The first answer, on line 3, takes the recommended defaults: line 4 lists them, ending with Agent feedback. The second, on line 5, asks each question one by one. If you've made a project before, create-next-app remembers your answers and adds a third choice between them: No, reuse previous settings.

Choose No, customize settings, and these are the questions. Each was answered here with Return, which keeps its default:

Every question, answered with its defaultText
✔ Would you like to use the recommended Next.js defaults? › No, customize settings
✔ Would you like to use TypeScript? … No / Yes
✔ Which linter would you like to use? › ESLint
✔ Would you like to use React Compiler? … No / Yes
✔ Would you like to use Tailwind CSS? … No / Yes
✔ Would you like your code inside a `src/` directory? … No / Yes
✔ Would you like to use App Router? (recommended) … No / Yes
✔ Would you like to use Cache Components? … No / Yes
✔ Would you like to customize the import alias (`@/*` by default)? … No / Yes
✔ Would you like to include AGENTS.md to guide coding agents to write up-to-date Next.js code? … No / Yes
✔ Would you like to help improve Next.js by letting agents prepare anonymized feedback for your review as you code? (Disable anytime with `experimental.agentFeedback: false`.) … No / Yes

A toggle shows No / Yes, and its default is the one already chosen when it appears. What each one means:

  • TypeScript (line 2, default Yes): the files end in .tsx, and TypeScript checks them.
  • Linter (line 3, default ESLint): a linter reads your code and warns about likely mistakes. ESLint has more rules; Biome is faster and also formats your code. The linting section compares them.
  • React Compiler (line 4, default No): a build step that makes your components skip work they don't need to redo, so you write fewer useMemo calls by hand. The React Compiler lesson shows it.
  • Tailwind CSS (line 5, default Yes): a CSS library where you style elements with class names like text-lg. (Styling components compares the ways to style React.)
  • src/ directory (line 6, default No): puts the app folder inside a folder named src, apart from the settings files.
  • App Router (line 7, default Yes): pages live in the app folder. No gives you the Pages Router, Next.js's older way, with a pages folder. It still works, but this course teaches the App Router.
  • Cache Components (line 8, default Yes): the way Next.js 16 decides what to prerender and what to cache, which this course teaches. It's been on by default for new apps since Next.js 16.4, from October 2026.
  • Import alias (line 9, default No): an import alias is a short name for the project's top folder. With @/*, any file can write import { getTeas } from "@/app/teas" instead of counting ../../ (import and export shows plain paths).
  • AGENTS.md (line 10, default Yes) and agent feedback (line 11, default Yes): two things for AI coding agents, in their own section.
Five answers on the left, each with an arrow to what it writes on the right. TypeScript writes tsconfig.json. ESLint writes eslint.config.mjs. Tailwind CSS adds the package at tailwindcss slash turbopack. Cache Components writes cacheComponents true in next.config.ts. AGENTS.md writes the file AGENTS.md.your answer: Yeswhat it writesTypeScripttsconfig.jsonESLinteslint.config.mjsTailwind CSS@tailwindcss/turbopackCache ComponentscacheComponents: trueAGENTS.mdAGENTS.md
Every Yes becomes a file, a package in package.json, or a line in next.config.ts. Answer No, and that part is left out.

Each row is one question, its default, and what a Yes adds to the project:

Every question and what it writes
QuestionIts defaultWhat a Yes writes
Would you like to use TypeScript?Yes.tsx files, tsconfig.json, next-env.d.ts, and typescript with its types in package.json.
Which linter would you like to use?ESLinteslint.config.mjs and a lint script. Biome writes biome.json instead. None writes neither.
Would you like to use React Compiler?NoreactCompiler: true in next.config.ts, and babel-plugin-react-compiler in package.json.
Would you like to use Tailwind CSS?Yestailwindcss and @tailwindcss/turbopack in package.json, and a turbopack rule in next.config.ts.
Would you like your code inside a src/ directory?Nosrc/app instead of app, and an @/* alias that points into src.
Would you like to use App Router?YesAn app folder. No writes a pages folder for the older Pages Router.
Would you like to use Cache Components?YescacheComponents: true and partialPrefetching: true in next.config.ts.
Would you like to customize the import alias?NoA Yes asks for your own alias instead of @/*.
Would you like to include AGENTS.md?YesAGENTS.md, the note that points coding agents at the docs in node_modules.
Would you like to help improve Next.js…?Yesexperimental: { agentFeedback: true } in next.config.ts.

Flags skip the questions

Every answer has a flag: an option you type after the command, starting with --. Give any flag, and create-next-app asks nothing. It uses the defaults for every question you didn't answer, and lists them:

A Biome project with a src folder, and no questionsShell
npx create-next-app@latest tea-shop --biome --src-dir

A run with only --skip-install and --disable-git, which aren't answers, printed every default it used:

What create-next-app printed for the answers it wasn't givenText
Using defaults for unprovided options:

  --ts                    TypeScript (use --js for JavaScript)
  --eslint                ESLint (use --biome for Biome, --no-eslint for None)
  --no-react-compiler     No React Compiler (use --react-compiler for React Compiler)
  --tailwind              Tailwind CSS (use --no-tailwind for No Tailwind CSS)
  --no-src-dir            No src/ directory (use --src-dir for src/ directory)
  --app                   App Router (use --no-app for Pages Router)
  --cache-components      Cache Components (use --no-cache-components for No Cache Components)
  --agents-md             AGENTS.md (use --no-agents-md for No AGENTS.md)
  --no-agent-feedback     No agent feedback (use --agent-feedback for Agent feedback)
  --import-alias          "@/*"

Each line is one default and its flag, with the other flags in brackets. --no- in front of a flag answers No, like --no-tailwind. Line 11 says agent feedback stays off unless you ask for it with --agent-feedback. npx create-next-app@latest --help lists every flag:

npx create-next-app@latest --helpText
Usage: create-next-app [directory] [options]

Options:
  -v, --version                            Output the current version of create-next-app.
  --ts, --typescript                       Initialize as a TypeScript project. (default)
  --js, --javascript                       Initialize as a JavaScript project.
  --tailwind                               Initialize with Tailwind CSS config. (default)
  --react-compiler                         Initialize with React Compiler enabled.
  --cache-components                       Initialize with Cache Components enabled.
  --eslint                                 Initialize with ESLint config.
  --biome                                  Initialize with Biome config.
  --app                                    Initialize as an App Router project.
  --src-dir                                Initialize inside a 'src/' directory.
  --rspack                                 Enable Rspack as the bundler.
  --import-alias <prefix/*>                Specify import alias to use (default "@/*").
  --api                                    Initialize a headless API using the App Router.
  --empty                                  Initialize an empty project.
  --use-npm                                Explicitly tell the CLI to bootstrap the application using npm.
  --use-pnpm                               Explicitly tell the CLI to bootstrap the application using pnpm.
  --use-yarn                               Explicitly tell the CLI to bootstrap the application using Yarn.
  --use-bun                                Explicitly tell the CLI to bootstrap the application using Bun.
  --reset, --reset-preferences             Reset the preferences saved for create-next-app.
  --skip-install                           Explicitly tell the CLI to skip installing packages.
  --yes                                    Use saved preferences or defaults for unprovided options.
  -e, --example <example-name|github-url>

    An example to bootstrap the app with. You can use an example name
    from the official Next.js repo or a public GitHub URL. The URL can use
    any branch and/or subdirectory.

  --example-path <path-to-example>

    In a rare case, your GitHub URL might contain a branch name with
    a slash (e.g. bug/fix-1) and the path to the example (e.g. foo/bar).
    In this case, you must specify the path to the example separately:
    --example-path foo/bar

  --agents-md                              Include AGENTS.md to guide coding agents to write up-to-date Next.js code. (default)
  --agent-feedback                         Prepare anonymized Next.js feedback for your review.
  --no-agent-feedback                      Do not prepare anonymized Next.js feedback for your review.
  --disable-git                            Skip initializing a git repository.
  -h, --help                               Display this help message.

--yes is a little different from the recommended defaults. It uses your saved answers (the ones create-next-app remembers from your last project) and the defaults for the rest, and it leaves agent feedback off. The recommended defaults from the first question turn agent feedback on: compare the next.config.ts they write with the one in the playground below.

next.config.ts from "Yes, use recommended defaults"TypeScript
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  /* config options here */
  experimental: {
    agentFeedback: true,
  },
  cacheComponents: true,
  partialPrefetching: true,
  turbopack: {
    rules: {
      "*.css": {
        loaders: ["@tailwindcss/turbopack"],
        as: "*.css",
      },
    },
  },
};

export default nextConfig;

Lines 5 to 7 are the only difference from the --yes project: experimental: { agentFeedback: true }. Try the flags below. Each button is a real run of create-next-app 16.4.3 with those flags. Before you click, guess which files each one adds or removes.

Playground: what does each flag change?
The files in tea-shop (17)Text
app/
  favicon.ico
  globals.css
  layout.tsx
  page.tsx
public/
  file.svg
  globe.svg
  next.svg
  vercel.svg
  window.svg
.gitignore
AGENTS.md
README.md
eslint.config.mjs
next-env.d.ts
next.config.ts
package.json
tsconfig.json
next.config.tsTypeScript
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  /* config options here */
  cacheComponents: true,
  partialPrefetching: true,
  turbopack: {
    rules: {
      "*.css": {
        loaders: ["@tailwindcss/turbopack"],
        as: "*.css",
      },
    },
  },
};

export default nextConfig;
Try it yourself
npx create-next-app@latest tea-shop

The defaults: TypeScript (tsconfig.json), ESLint (eslint.config.mjs), Tailwind CSS and the App Router. next.config.ts turns on Cache Components, and its turbopack rule sends every CSS file through Tailwind's loader.

Every run is real: create-next-app 16.4.3 with these flags, run with --skip-install and --disable-git, so the lists leave out node_modules, package-lock.json and .git. Reset goes back to the run with no flags.

Most flags change one or two files. --src-dir moves the app folder, --js renames almost everything, and --empty leaves out the starter page's styles and pictures. A flag like --no-cache-components only changes a line in next.config.ts.

What's in the new project

Open the folder that npx create-next-app@latest tea-shop --yes made. The playground's No flags run lists its files. Three of them hold the settings. First, package.json:

package.jsonJSON
{
  "name": "tea-shop",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "eslint"
  },
  "dependencies": {
    "next": "16.4.3",
    "react": "19.3.0",
    "react-dom": "19.3.0"
  },
  "devDependencies": {
    "@tailwindcss/turbopack": "^4",
    "@types/node": "^20",
    "@types/react": "^19",
    "@types/react-dom": "^19",
    "eslint": "^9",
    "eslint-config-next": "16.4.3",
    "tailwindcss": "^4",
    "typescript": "^5"
  }
}
  • Lines 5 to 10 are the scripts: short names for commands. npm run dev runs next dev, and so on. lint, on line 9, runs ESLint.
  • Lines 11 to 15 are the dependencies: next 16.4.3 and the React 19.3.0 it was released with. These versions have no ^ in front, so every install gets exactly these.
  • Lines 16 to 25 are the tools: TypeScript and the types for Node.js and React, ESLint with Next.js's rules on line 22, and Tailwind CSS with its Turbopack loader on line 17.

Then next.config.ts, Next.js's own settings:

next.config.tsTypeScript
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  /* config options here */
  cacheComponents: true,
  partialPrefetching: true,
  turbopack: {
    rules: {
      "*.css": {
        loaders: ["@tailwindcss/turbopack"],
        as: "*.css",
      },
    },
  },
};

export default nextConfig;

Line 3 makes an object with the type NextConfig, so your editor knows every option. Lines 5 and 6 turn on Cache Components and Partial Prefetching. Lines 7 to 14 tell Turbopack to send every .css file through Tailwind's loader, on line 10: that's how the class names become CSS. Line 17 exports the object, and Next.js reads it whenever it starts.

The rest, in short:

  • tsconfig.json holds TypeScript's settings, including the @/* alias. next-env.d.ts is written by Next.js, for TypeScript; you never edit it.
  • .gitignore tells git which files not to save: node_modules, the .next folder the build writes, and .env files, which hold secrets.
  • app/ holds the pages: layout.tsx, page.tsx, globals.css and the site's icon, favicon.ico. public/ holds five pictures the starter page shows.
  • README.md says how to run the project, and AGENTS.md is for coding agents.

Where each kind of file goes, and why, is the next lesson. Here the point is the settings: they're ordinary files, and you can change them later. Answering a question differently only saves you writing them.

next dev, next build and next start

package.json gave you three scripts that run Next.js. They come in two kinds: development, while you write the app, and production, the finished app that visitors use.

npm run dev, while you work

npm run dev runs next dev, the development server: a server on your own computer, at http://localhost:3000. localhost means this computer, and 3000 is the port, a number that tells programs on one computer apart. It prints ▲ Next.js 16.4.3 (Turbopack), then the address, then ✓ Ready, then that Cache Components and Partial Prefetching are on. (The (Turbopack) and those last two lines only appear for next dev: logStartInfo prints the first part, and start-server.ts passes logBundler: isDev.)

Next.js's docs describe what it does next (this lesson doesn't run the development server). It builds each page the first time you open it, not before. Save a file, and it builds that part again, and the open browser tab updates by itself. This is called Fast Refresh. It tries to keep the state of your function components while it swaps in the new code, when that's safe. Some edits reset that state, like a change to a file that exports more than components, and an edit to a file used outside React reloads the whole page. If your code has an error, it shows on the page in an overlay, with the file and line. Edit app/page.tsx into the tea shop's home page, and you see the teas a moment after you save.

That same edited page is below, built and run in production. The Browser tab shows the page. The Terminal tab shows what next build printed, then what next start printed.

The tea shop's home page, after the first editNext.js
app/
app/page.tsx
const teas = [  { name: "Green tea", price: 4 },  { name: "Mint tea", price: 3 },  { name: "Lemon tea", price: 3 },]; export default function Home() {  return (    <main>      <h1>Tea shop</h1>      <ul>        {teas.map((tea) => (          <li key={tea.name}>            {tea.name}: ${tea.price}          </li>        ))}      </ul>    </main>  );}
Recorded from Next.js 16.4.3
localhost:3000/Create Next App
Tea shop
  • Green tea: $4
  • Mint tea: $3
  • Lemon tea: $3

The page as the browser shows it when its HTML arrives, drawn with plain styles. Its JavaScript doesn't run here.

npm run build, for the finished app

npm run build runs next build. It builds every page at once and writes the finished app into a folder named .next. Open the Terminal tab and read it from the top:

  1. ▲ Next.js 16.4.3 (Turbopack): the version, and the bundler. The next two lines say Cache Components and Partial Prefetching are on, from next.config.ts.
  2. Creating an optimized production build and ✓ Compiled successfully: Turbopack turned your files into the code browsers and the server run.
  3. Running TypeScript and Finished TypeScript: Next.js checked the types of every file.
  4. Collecting page data and Generating static pages: Next.js ran your pages and saved the HTML of the ones it could make ahead of time.
  5. Route (app): every address the app has. ○ / is the home page, prerendered as static content, and /_not-found is the page Next.js adds for addresses that don't exist.

The times are left out of the recording, because they change on every run. In your own terminal, every step says how long it took, and the steps that use several workers (helper processes, so the work runs side by side) say how many. This is the build of the default project from --yes, with its Tailwind CSS, in full:

npm run build in the default projectText
> tea-shop@0.1.0 build
> next build

▲ Next.js 16.4.3 (Turbopack)
✓ Running next.config.ts took 63ms
- Cache Components enabled
- Partial Prefetching enabled

  Creating an optimized production build ...
✓ Compiled successfully in 2.6s
  Running TypeScript ...
  Finished TypeScript in 1154ms ...
  Collecting page data using 5 workers ...
  Generating static pages using 5 workers (0/4) ...
  Generating static pages using 5 workers (1/4)
  Generating static pages using 5 workers (2/4)
  Generating static pages using 5 workers (3/4)
✓ Generating static pages using 5 workers (4/4) in 315ms
  Finalizing page optimization ...

Route (app)
┌ ○ /
└ ○ /_not-found

○  (Static)  prerendered as static content

Lines 1 and 2 are npm saying which script it runs. Line 5 is new: Next.js read next.config.ts before anything else. Lines 14 to 18 are the page counter, from 0 to 4. A terminal draws them over each other on one line; here they were printed one after another. Lines 21 to 25 are the same route table as the recording.

npm run start, to serve it

npm run start runs next start, the production server. It builds nothing: it serves what next build wrote into .next, the way a host would. In the Terminal tab, it printed its address and ✓ Ready. The recorder asks it to listen on 127.0.0.1, another name for this computer; run on your own, it says localhost, and also prints a Network address, which other devices on your wifi can open. Here it is on the computer the lessons were made on (the network address is replaced):

next start, run in the default projectText
▲ Next.js 16.4.3
- Local:         http://localhost:3000
- Network:       http://192.168.1.20:3000
✓ Ready in 141ms
✓ Running next.config.ts took 78ms

Production is two steps, and development is one:

Left, development: npm run dev starts a server at localhost 3000 that builds each page when you open it, and again when you save. Right, production: npm run build writes the finished app into the .next folder, then npm run start serves it at localhost 3000.Developmentnpm run devbrowserlocalhost:3000built again when you saveProduction1. npm run build.next2. npm run startserves the finished app
In development, npm run dev does it all: it builds a page when you open it, and again when you save a file. For production it's two steps: npm run build writes the finished app into .next, and npm run start serves what's there.

Each row asks one question of both:

Development and production
Questionnpm run devnpm run build, then npm run start
When do you use it?While you write the app, on your own computer.To try or run the finished app, the way visitors get it.
When is a page built?When you first open it, and again when you save a file it uses.All at once, by next build, before the server starts.
What does it check?It shows errors on the page as you work.next build checks types in every file, and stops on an error.
What does it print first?▲ Next.js 16.4.3 (Turbopack), the address, and that Cache Components are on.▲ Next.js 16.4.3, the address and ✓ Ready.

next build also checks your code before it makes anything. Try it below. Each button is one version of app/page.tsx, built with real Next.js. Before you click, guess which ones build.

Playground: what does next build check?
The tea shop, with this version of app/page.tsxNext.js
app/
app/page.tsx
const teas = [  { name: "Green tea", price: 4 },  { name: "Mint tea", price: 3 },  { name: "Lemon tea", price: 3 },]; export default function Home() {  return (    <main>      <h1>Tea shop</h1>      <ul>        {teas.map((tea) => (          <li key={tea.name}>            {tea.name}: ${tea.price}          </li>        ))}      </ul>    </main>  );}
Recorded from Next.js 16.4.3
$ next build▲ Next.js 16.4.3 (Turbopack)- Cache Components enabled- Partial Prefetching enabled   Creating an optimized production build ...✓ Compiled successfully  Running TypeScript ...  Finished TypeScript ...  Collecting page data ...✓ Generating static pages (3/3)  Finalizing page optimization ... Route (app)┌ ○ /└ ○ /_not-found ○  (Static)  prerendered as static content $ next start▲ Next.js 16.4.3- Local:         http://127.0.0.1:3000- Network:       http://127.0.0.1:3000✓ Ready
Try it yourself
The tea page

TypeScript finds nothing wrong, the page is prerendered, and the route table lists ○ /. There's no linting step in the output: next build doesn't run ESLint.

Every version was built with next build from Next.js 16.4.3, and the Terminal shows what it printed. Only app/page.tsx changes. Reset goes back to the first version.

The tea page and the plain <img> both build. The type error stops at Running TypeScript, with app/page.tsx(10,27): line 10, column 27, where amount gets the text "4". The missing file stops even earlier, while Turbopack compiles. Either way, nothing is written, so next start would have no new app to serve.

Turbopack, the bundler

Your app is many small files, called modules, and each imports others. Browsers can't read TypeScript or JSX at all. A bundler follows the imports from each page, turns the code into plain JavaScript, and writes it out as files called chunks: some shared by every route, and some that belong to one route, so each route loads the code it needs and no more. Next.js's bundler is Turbopack, written in Rust and built into the next package. You never install or start it yourself.

Since Next.js 16 (October 2025), Turbopack is the default for both next dev and next build. That's what the (Turbopack) in ▲ Next.js 16.4.3 (Turbopack) says. In Next.js 15, development could use it with next dev --turbo, and builds used webpack, the bundler Next.js used before. A project with its own webpack settings can still choose webpack with next dev --webpack and next build --webpack.

You can see Turbopack's work in two places:

  • In the tea page's Network tab above, the HTML loads <script> files from /_next/static/chunks/, and one of them is named turbopack- followed by letters. Those are the chunks.
  • In the playground's A missing file version, the build stops with Turbopack build failed with 1 error: it couldn't follow the import on line 1, because ./teas doesn't exist.

Turbopack also keeps what it has already built in a cache on disk, so next dev starts faster the next time. That has been on by default since Next.js 16.1. When you use Tailwind CSS, the turbopack rule in next.config.ts is Turbopack's only setting in a new project.

Checking code with ESLint or Biome

A linter reads your code without running it and warns about likely mistakes. The default project uses ESLint, with this eslint.config.mjs:

eslint.config.mjsJavaScript
import { defineConfig, globalIgnores } from "eslint/config";
import nextVitals from "eslint-config-next/core-web-vitals";
import nextTs from "eslint-config-next/typescript";

const eslintConfig = defineConfig([
  ...nextVitals,
  ...nextTs,
  // Override default ignores of eslint-config-next.
  globalIgnores([
    // Default ignores of eslint-config-next:
    ".next/**",
    "out/**",
    "build/**",
    "next-env.d.ts",
  ]),
]);

export default eslintConfig;

Lines 2 and 3 load Next.js's two sets of rules from eslint-config-next: core-web-vitals, about pages that load fast, and typescript. Lines 6 and 7 use them. Lines 9 to 15 list folders ESLint skips, like the build's .next. Run it with npm run lint. This page uses a plain <img>:

app/page.tsx with a plain imgTSX
export default function Home() {
  return (
    <main>
      <h1>Tea shop</h1>
      <img src="/green-tea.png" alt="A cup of green tea" />
    </main>
  );
}

And this is what npm run lint printed for it:

npm run lintText
> tea-shop@0.1.0 lint
> eslint

~/projects/tea-shop/app/page.tsx
  5:7  warning  Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` or a custom image loader to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element  @next/next/no-img-element

✖ 1 problem (0 errors, 1 warning)

Line 4 names the file. Line 5 says where (line 5, column 7), how serious it is (warning), what's wrong, and the rule's name at the end: @next/next/no-img-element. next/image's Image loads pictures in the right size; a later lesson teaches it. Line 7 counts the problems.

The build playground's A plain <img> version is this same page, and it built. Since Next.js 16, next build doesn't run the linter, and the next lint command is gone (it was deprecated in Next.js 15.5). You run npm run lint yourself, or your editor shows the same warnings as you type.

Choose Biome instead, and create-next-app writes biome.json. Biome is one fast tool that lints and formats, with fewer rules than ESLint:

biome.jsonJSON
{
  "$schema": "https://biomejs.dev/schemas/2.4.2/schema.json",
  "vcs": {
    "enabled": true,
    "clientKind": "git",
    "useIgnoreFile": true
  },
  "files": {
    "ignoreUnknown": true,
    "includes": ["**", "!node_modules", "!.next", "!dist", "!build"]
  },
  "formatter": {
    "enabled": true,
    "indentStyle": "space",
    "indentWidth": 2
  },
  "css": {
    "parser": {
      "tailwindDirectives": true
    }
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true
    },
    "domains": {
      "next": "recommended",
      "react": "recommended"
    }
  },
  "assist": {
    "actions": {
      "source": {
        "organizeImports": "on"
      }
    }
  }
}

Lines 12 to 16 turn on its formatter, which rewrites your code's spacing the same way every time. Lines 22 to 31 turn on its linter, with its recommended rules and its rule groups for Next.js and React on lines 28 and 29. Each row compares the two:

ESLint and Biome in a new project
QuestionESLintBiome
Which file holds its settings?eslint.config.mjsbiome.json
What does npm run lint run?eslintbiome check
Does the new project have a formatting script?No. package.json only gets lint.Yes: npm run format runs biome format --write.
Does it know Next.js's rules?Yes: eslint-config-next, like the <img> warning.Yes: its next and react rule groups, which have fewer rules.

Either works. This course's recorded examples use neither, so their projects stay small.

AGENTS.md and docs for coding agents

A coding agent is an AI tool that writes and changes code in your project, like Claude Code, Codex, Cursor or GitHub Copilot. It learned from code written before it was made, so it may know an older Next.js and write code that no longer works. AGENTS.md is a plain text file in the project's top folder that many agents read when they start. The one create-next-app writes says:

AGENTS.mdText
<!-- BEGIN:nextjs-agent-rules -->

## This is NOT the Next.js you know

This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` (resolved from this file's directory; in monorepos the `next` package may not be visible from the repo root) before writing any code. Heed deprecation notices.

This block is written and re-added by `next dev` — verify at `node_modules/next/dist/server/lib/generate-agent-files.js`. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean.

<!-- END:nextjs-agent-rules -->

Lines 1 and 9 are markers: they let Next.js find its own part of the file, so you can add your own notes above or below them. Line 5 is the instruction: read the guide in node_modules/next/dist/docs/ before writing code. Since Next.js 16.2, the next package has its whole documentation inside it, as Markdown files that match the installed version (474 files in 16.4.3). An agent reads the docs for your Next.js, not what it remembers.

Line 7 says next dev puts the block back if it's removed. It does that only when it sees it was started by a coding agent. To turn this off, set agentRules: false in next.config.ts; to leave the file out of a new project, pass --no-agents-md. Next.js 16.2 and 16.3 also wrote a CLAUDE.md that pointed at AGENTS.md; since 16.4, it's only AGENTS.md.

The last question, agent feedback, is an experimental option: when an agent hits a problem with Next.js itself, it prepares a report with your project's details removed, and shows it to you in the browser. Nothing is sent until you press Send. It's the experimental.agentFeedback line from the recommended defaults.

Starting the tea shop, step by step

Here is the whole start of a project, in the order you'd do it:

  1. Check node -v says 20.9 or newer.
  2. Run npx create-next-app@latest tea-shop, and answer the questions, or add --yes or flags.
  3. cd tea-shop, then npm run dev, and open http://localhost:3000.
  4. Edit app/page.tsx and save. The open tab updates.
  5. Run npm run lint now and then, and fix what it warns about.
  6. Before you put it online, stop the development server with Control and C, run npm run build, and try the result with npm run start.

Each card below is a moment in that work. Sort it under the script you'd run:

Which script do you run?
  • You changed app/page.tsx and want to see it in the browser right away.
  • You just created the project and want to open it at localhost:3000.
  • You want to know if any file in the project has a type error.
  • You're about to put the shop online and want to know it builds.
  • The build passed, and you want to try the finished app the way visitors will get it.
  • You want a warning about every plain <img> in the project.
Try it yourself
0 of 6 correct

Sort each moment under the script that does what you need.

Choose a category for every card. You can change an answer at any time; Reset clears them all.

Common mix-ups

  • "You need create-next-app to use Next.js." No. It only writes files and installs packages. You can install next, react and react-dom yourself and write the same files.
  • "--yes is the same as the recommended defaults." No. It reuses your saved answers first, and leaves agent feedback off.
  • "npm run start builds the app." No. It serves what npm run build wrote into .next, and stops with an error when there's nothing there.
  • "next build stops on lint warnings." Not since Next.js 16. It checks types, not lint rules. Run npm run lint yourself.
  • "Turbopack is a package you install." No. It's part of next, and the default bundler since Next.js 16.
  • "The development server shows how fast the real site is." No. It builds pages when you open them and adds tools for you. Measure speed with npm run build and npm run start.
  • "AGENTS.md changes how the app runs." No. It's a note for coding agents. Next.js reads next.config.ts, never AGENTS.md.

Practice exercises

Answer first, then use the hints.

Exercise 1 · Warm-upIs this Node.js new enough?

A computer prints this. Can it run Next.js 16.4.3?

Starter codeText
$ node -v
v18.20.4

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · Warm-upPick the script for your first look

    You just made the project. Which command do you type to open it in the browser?

    Starter codeJSON
    {
      "name": "tea-shop",
      "version": "0.1.0",
      "private": true,
      "scripts": {
        "dev": "next dev",
        "build": "next build",
        "start": "next start",
        "lint": "eslint"
      },
      "dependencies": {
        "next": "16.4.3",
        "react": "19.3.0",
        "react-dom": "19.3.0"
      },
      "devDependencies": {
        "@tailwindcss/turbopack": "^4",
        "@types/node": "^20",
        "@types/react": "^19",
        "@types/react-dom": "^19",
        "eslint": "^9",
        "eslint-config-next": "16.4.3",
        "tailwindcss": "^4",
        "typescript": "^5"
      }
    }
    

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticeWrite the command

      Write one command that makes tea-shop with Biome and a src folder, and asks no questions.

      Answer, then press Check. Spacing and letter case don’t matter.

        Exercise 4 · PracticeFix the type error

        The build stops on line 10 of this app/page.tsx. Rewrite that line so it builds.

        Starter codeTSX
        function Price({ amount }: { amount: number }) {
          return <span>${amount}</span>;
        }
        
        export default function Home() {
          return (
            <main>
              <h1>Tea shop</h1>
              <p>
                Green tea: <Price amount="4" />
              </p>
            </main>
          );
        }
        

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · ChallengeRead the error from npm run start

          A teammate cloned the tea shop, ran npm install, then npm run start, and got this. What do they run first?

          Starter codeText
          > tea-shop@0.1.0 start
          > next start
          
          ▲ Next.js 16.4.3
          - Local:         http://localhost:3000
          - Network:       http://192.168.1.20:3000
          ✓ Ready in 140ms
          ✓ Running next.config.ts took 77ms
          Error: Could not find a production build in the '.next' directory. Try building your app with 'next build' before starting the production server. https://nextjs.org/docs/messages/production-start-no-build-id
              at ignore-listed frames

          Answer, then press Check. Spacing and letter case don’t matter.

            Exercise 6 · ChallengePredict the build with a lint warning

            npm run lint warns about this page. Does npm run build pass?

            Starter codeTSX
            export default function Home() {
              return (
                <main>
                  <h1>Tea shop</h1>
                  <img src="/green-tea.png" alt="A cup of green tea" />
                </main>
              );
            }
            

            Answer, then press Check. Spacing and letter case don’t matter.

              Check your understanding

              For each question, think about which program runs, and what it reads or writes.

              The Creating a Next.js app quiz · 7 questionsScore: first tries count
              1. Question 1 of 7What does --yes do when you run npx create-next-app@latest tea-shop --yes?

                Choose an answer to see the explanation.

              2. Question 2 of 7Which Node.js versions can run Next.js 16.4.3?

                Choose an answer to see the explanation.

              3. Question 3 of 7This is what npm run start printed. What went wrong?

                Read the code, then predictText
                > tea-shop@0.1.0 start
                > next start
                
                ▲ Next.js 16.4.3
                - Local:         http://localhost:3000
                - Network:       http://192.168.1.20:3000
                ✓ Ready in 140ms
                ✓ Running next.config.ts took 77ms
                Error: Could not find a production build in the '.next' directory. Try building your app with 'next build' before starting the production server. https://nextjs.org/docs/messages/production-start-no-build-id
                    at ignore-listed frames

                Choose an answer to see the explanation.

              4. Question 4 of 7In the build playground, this page's build stops. At which step?

                Read the code, then predictTSX
                function Price({ amount }: { amount: number }) {
                  return <span>${amount}</span>;
                }
                
                export default function Home() {
                  return (
                    <main>
                      <h1>Tea shop</h1>
                      <p>
                        Green tea: <Price amount="4" />
                      </p>
                    </main>
                  );
                }
                

                Choose an answer to see the explanation.

              5. Question 5 of 7Does next build pass with this page, which npm run lint warns about?

                Read the code, then predictTSX
                export default function Home() {
                  return (
                    <main>
                      <h1>Tea shop</h1>
                      <img src="/green-tea.png" alt="A cup of green tea" />
                    </main>
                  );
                }
                

                Choose an answer to see the explanation.

              6. Question 6 of 7Which bundler does a new Next.js 16 project use for next dev and next build?

                Choose an answer to see the explanation.

              7. Question 7 of 7What is AGENTS.md in a new project for?

                Choose an answer to see the explanation.

              Key takeaways

              • npx create-next-app@latest writes a project and installs its packages. It needs Node.js 20.9.0 or newer.
              • Its questions, or their flags, choose TypeScript, a linter, Tailwind CSS, a src folder, the App Router and Cache Components. Each Yes becomes a file or a line in one. --yes uses your saved answers, then the defaults.
              • npm run dev runs the development server, which builds pages as you open and save them. npm run build builds everything into .next and checks types, and npm run start serves that build.
              • Turbopack is Next.js's bundler, built in, and the default for development and builds since Next.js 16.
              • npm run lint runs ESLint or Biome. next build doesn't lint any more.
              • AGENTS.md points coding agents at the docs inside node_modules/next/dist/docs/, which match your version.

              Remember the one-liner.
              create-next-app writes the project; dev runs it while you work; build makes it and start serves it.

              Read it in Next.js's own code

              The defaults create-next-app uses are one object, at lines 246 to 260 of create-next-app/index.ts, and the recommended defaults add agentFeedback: true on lines 262 to 265. The AGENTS.md it writes comes from helpers/generate-agent-files.ts. All links point at release v16.4.3.

              Coming next: Project structure. It goes through the folders and files you just made: app, the special files in it, public, src and next.config.ts.

              CompleteFrontend Clear concepts. Working examples.