Setting up a project with create-next-app
Every CLI flag that shapes the project, the folder layout it produces, and which config files you will actually edit.
create-next-app and its flags
npx create-next-app@latest my-app \
--ts --app --eslint --tailwind --src-dir --turbopack \
--import-alias "@/*"
cd my-app
npm run dev # http://localhost:3000
npm run build # production build into .next/
npm start # serve the build (never in development)| Flag | Effect |
|---|---|
--ts / --js | TypeScript or JavaScript source files |
--app | App Router (app/) instead of the Pages Router |
--src-dir | Put the router inside src/ rather than the project root |
--eslint | Add the Next.js ESLint config and a lint script |
--tailwind | Wire up Tailwind and a global stylesheet |
--import-alias | Map @/* to the root or to src/ |
--turbopack | Use Turbopack as the dev and build bundler |
- The CLI writes a project and prints the next steps. It does not update itself afterwards; the versions it pinned live in
package.json, so commit the lockfile. - Answer in the interactive prompt or pass the flags — both work, and the flags make the setup reproducible in a script.
- Pin the Node version with an
enginesfield or an.nvmrc. A build server on an older Node is one of the most common CI failures. - A tutorial written for the Pages Router will not match what this generates. Check the import path in any example before copying it.
The folder layout
my-app/ (with --src-dir)
src/app/
layout.tsx required root layout: renders html and body
page.tsx the / route
globals.css imported once by the root layout
favicon.ico
public/ served from /, copied unprocessed
next.config.ts framework configuration
tsconfig.json paths: { "@/*": ["./src/*"] }
eslint.config.mjs
package.jsonRoutes are created by file names, not by registration. Only page, layout, route, loading, error, not-found and a few siblings become routes; a helper file next to a page is just a module.
- With
--src-dirthe router lives insrc/app; without it,app/sits at the project root. The import alias must point at whichever one you chose. public/logo.pngis served as/logo.png, with no hashing and no optimisation. An image imported from code goes through the build instead.- Files imported by a server component stay on the server, so a database client in
src/lib/db.tsnever reaches the browser bundle. - Only add
'use client'where you need state, events or browser APIs. Everything else stays a server component by default.
The config files you will edit
// next.config.ts
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
reactStrictMode: true,
images: {
remotePatterns: [{ protocol: 'https', hostname: 'images.example.com' }]
},
async redirects() {
return [{ source: '/old-guide', destination: '/guides/intro', permanent: true }]
}
}
export default nextConfig- The config file is executed by Node at build time, so it cannot read anything about an incoming request. Per-request behaviour belongs in middleware.
next devruns Turbopack for a fast inner loop;next buildcan use it too. If one of your loaders is not supported yet, that is a signal to check, not a reason to avoid the bundler.next buildprints a route table that marks each route static or dynamic. Read it after a change — it is the fastest way to see an accidental per-request render.- The TypeScript
pathsentry and the Next.js alias must agree. A mismatch shows up as a module-not-found error even though the file exists. redirectsandrewritesin the config run before your routes, which makes them the cheapest place to handle a URL migration.
💡
The root layout is required and is the only place that may render
html and body. Every route under app/ depends on it, so a build failure across the whole site usually starts there.FAQ
App Router or Pages Router?
The App Router for anything new: server components, nested layouts, streaming and server actions all live there. The Pages Router still works and existing apps can stay on it, but new examples and features assume
app/.Is Turbopack ready to use?
It is the default for development and is used by the build as well. If a specific webpack loader or plugin is not supported, the failure is explicit and you can fall back for that build — but check first that the plugin is still needed.
Related
Routing, links and navigation Dynamic routes, params and metadata
Last refreshed 2026-09-18.