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.
- 01Create a projectRun create-next-app with its questions or with flags, and say what each answer writes into the project.
- 02Run it two waysUse next dev while you work, and next build then next start for the finished app, and read what each one prints.
- 03Know 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:
npx create-next-app@latest tea-shop --yes
cd tea-shop
npm run devYou 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.)
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-shopRead it from the top:
- Line 1 makes the folder. Line 3 says it uses npm, because
npxis 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
LayoutPropsyou'll meet below. Line 34 starts a git repository, so you can save versions of your work. Line 36 says it's done.
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.
create-next-app --empty --no-tailwind --no-linter makesNext.jsapp/page.tsxexport default function Home() { return ( <main> <div>Hello world!</div> </main> );}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.
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,publicand 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, thennpm run startto 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
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:
node -vOn 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 you need | Which version | How to check |
|---|---|---|
| Node.js | 20.9 or newer. Next.js 16 stopped supporting Node.js 18. | Run node -v in a terminal. |
| A package manager | npm comes with Node.js. pnpm, Yarn and Bun work too. | create-next-app prints Using npm. (or the one you used). |
| TypeScript | 5.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 system | macOS, 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:
✔ 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 settingsLine 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:
✔ 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 / YesA 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
useMemocalls 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 theappfolder inside a folder namedsrc, apart from the settings files.- App Router (line 7, default Yes): pages live in the
appfolder. No gives you the Pages Router, Next.js's older way, with apagesfolder. 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 writeimport { 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.
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:
| Question | Its default | What 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? | ESLint | eslint.config.mjs and a lint script. Biome writes biome.json instead. None writes neither. |
| Would you like to use React Compiler? | No | reactCompiler: true in next.config.ts, and babel-plugin-react-compiler in package.json. |
| Would you like to use Tailwind CSS? | Yes | tailwindcss and @tailwindcss/turbopack in package.json, and a turbopack rule in next.config.ts. |
Would you like your code inside a src/ directory? | No | src/app instead of app, and an @/* alias that points into src. |
| Would you like to use App Router? | Yes | An app folder. No writes a pages folder for the older Pages Router. |
| Would you like to use Cache Components? | Yes | cacheComponents: true and partialPrefetching: true in next.config.ts. |
| Would you like to customize the import alias? | No | A Yes asks for your own alias instead of @/*. |
| Would you like to include AGENTS.md? | Yes | AGENTS.md, the note that points coding agents at the docs in node_modules. |
| Would you like to help improve Next.js…? | Yes | experimental: { 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:
npx create-next-app@latest tea-shop --biome --src-dirA run with only --skip-install and --disable-git, which aren't answers, printed every default it used:
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:
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.
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.
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.jsonimport 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;
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.
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:
{
"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 devrunsnext dev, and so on.lint, on line 9, runs ESLint. - Lines 11 to 15 are the dependencies:
next16.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:
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.jsonholds TypeScript's settings, including the@/*alias.next-env.d.tsis written by Next.js, for TypeScript; you never edit it..gitignoretells git which files not to save:node_modules, the.nextfolder the build writes, and.envfiles, which hold secrets.app/holds the pages:layout.tsx,page.tsx,globals.cssand the site's icon,favicon.ico.public/holds five pictures the starter page shows.README.mdsays how to run the project, andAGENTS.mdis 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.
app/page.tsxconst 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> );}- 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:
▲ Next.js 16.4.3 (Turbopack): the version, and the bundler. The next two lines say Cache Components and Partial Prefetching are on, fromnext.config.ts.Creating an optimized production buildand✓ Compiled successfully: Turbopack turned your files into the code browsers and the server run.Running TypeScriptandFinished TypeScript: Next.js checked the types of every file.Collecting page dataandGenerating static pages: Next.js ran your pages and saved the HTML of the ones it could make ahead of time.Route (app): every address the app has.○ /is the home page, prerendered as static content, and/_not-foundis 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:
> 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 contentLines 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.js 16.4.3
- Local: http://localhost:3000
- Network: http://192.168.1.20:3000
✓ Ready in 141ms
✓ Running next.config.ts took 78msProduction is two steps, and development is one:
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:
| Question | npm run dev | npm 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.
app/page.tsxNext.jsapp/page.tsxconst 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> );}$ 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✓ ReadyTypeScript 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.
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 namedturbopack-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./teasdoesn'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:
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>:
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:
> 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:
{
"$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:
| Question | ESLint | Biome |
|---|---|---|
| Which file holds its settings? | eslint.config.mjs | biome.json |
What does npm run lint run? | eslint | biome 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:
<!-- 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:
- Check
node -vsays 20.9 or newer. - Run
npx create-next-app@latest tea-shop, and answer the questions, or add--yesor flags. cd tea-shop, thennpm run dev, and openhttp://localhost:3000.- Edit
app/page.tsxand save. The open tab updates. - Run
npm run lintnow and then, and fix what it warns about. - Before you put it online, stop the development server with Control and C, run
npm run build, and try the result withnpm run start.
Each card below is a moment in that work. Sort it under the script you'd run:
- You changed
app/page.tsxand 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.
Sort each moment under the script that does what you need.
Common mix-ups
- "You need create-next-app to use Next.js." No. It only writes files and installs packages. You can install
next,reactandreact-domyourself and write the same files. - "
--yesis the same as the recommended defaults." No. It reuses your saved answers first, and leaves agent feedback off. - "
npm run startbuilds the app." No. It serves whatnpm run buildwrote into.next, and stops with an error when there's nothing there. - "
next buildstops on lint warnings." Not since Next.js 16. It checks types, not lint rules. Runnpm run lintyourself. - "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 buildandnpm run start. - "
AGENTS.mdchanges how the app runs." No. It's a note for coding agents. Next.js readsnext.config.ts, neverAGENTS.md.
Practice exercises
Answer first, then use the hints.
A computer prints this. Can it run Next.js 16.4.3?
$ node -v
v18.20.4No. Next.js 16.4.3 needs Node.js 20.9.0 or newer, and 18 is below 20. Install the current long-term support version first, then run create-next-app.
You just made the project. Which command do you type to open it in the browser?
{
"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"
}
}
npm run dev. Line 6 maps dev to next dev, the development server at http://localhost:3000. start would fail, because nothing is built yet.
Write one command that makes tea-shop with Biome and a src folder, and asks no questions.
npx create-next-app@latest tea-shop --biome --src-dirGiving any flag skips the questions, and the others keep their defaults: TypeScript, Tailwind CSS, the App Router and Cache Components. The playground's --biome and --src-dir runs show what each one changes.
The build stops on line 10 of this app/page.tsx. Rewrite that line so it builds.
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>
);
}
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>
);
}
<Price amount={4} /> passes the number 4. The recorded build of the fixed page passes its TypeScript step and lists ○ /.
A teammate cloned the tea shop, ran npm install, then npm run start, and got this. What do they run first?
> 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 framesnpm run build first. next start only serves a build, and line 9 says there is none in .next. After the build, npm run start serves it.
npm run lint warns about this page. Does npm run build pass?
export default function Home() {
return (
<main>
<h1>Tea shop</h1>
<img src="/green-tea.png" alt="A cup of green tea" />
</main>
);
}
Yes. The <img> warning comes from ESLint, and next build doesn't run ESLint since Next.js 16. The recorded build prints ○ /. The warning still matters: run npm run lint and switch to next/image when you can.
Check your understanding
For each question, think about which program runs, and what it reads or writes.
Question 1 of 7What does
--yesdo when you runnpx create-next-app@latest tea-shop --yes?Choose an answer to see the explanation.
Question 2 of 7Which Node.js versions can run Next.js 16.4.3?
Choose an answer to see the explanation.
Question 3 of 7This is what
npm run startprinted. 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 framesChoose an answer to see the explanation.
Question 4 of 7In the build playground, this page's build stops. At which step?
Read the code, then predictTSXfunction 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.
Question 5 of 7Does
next buildpass with this page, whichnpm run lintwarns about?Read the code, then predictTSXexport 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.
Question 6 of 7Which bundler does a new Next.js 16 project use for
next devandnext build?Choose an answer to see the explanation.
Question 7 of 7What is
AGENTS.mdin a new project for?Choose an answer to see the explanation.
Key takeaways
npx create-next-app@latestwrites 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
srcfolder, the App Router and Cache Components. Each Yes becomes a file or a line in one.--yesuses your saved answers, then the defaults. npm run devruns the development server, which builds pages as you open and save them.npm run buildbuilds everything into.nextand checks types, andnpm run startserves that build.- Turbopack is Next.js's bundler, built in, and the default for development and builds since Next.js 16.
npm run lintruns ESLint or Biome.next builddoesn't lint any more.AGENTS.mdpoints coding agents at the docs insidenode_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.
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.