LearnFrenzy
Sign in Take a free test

Getting Started with Next.js · Lesson 2 of 24

Create a Next.js App: Setup and Project Structure

5 min read Updated Nov 8, 2026 Saurabh Samir

One command creates a complete Next.js project with TypeScript, Tailwind CSS, ESLint and the App Router already configured. This lesson walks through that command, then explains every file it creates, so nothing in the project is a mystery.

In this lesson

  • Creating a project with create-next-app
  • The files and folders, one by one
  • next.config.ts and Cache Components
  • The dev, build and start scripts

Create the project

You need Node.js 20.9 or newer. Then run:

npx create-next-app@latest my-next-app --yes
cd my-next-app
npm run dev

--yes accepts the recommended defaults: TypeScript, ESLint, Tailwind CSS, the App Router, Turbopack, and the @/* import alias. Without it, the tool asks about each one. Open http://localhost:3000 to see the starter page.

The project structure

my-next-app

  • app/ – routes, layouts and pages (the App Router)
    • layout.tsx – the root layout: the <html> and <body> around every page
    • page.tsx – the home page, /
    • globals.css – global styles; imports Tailwind
    • favicon.ico – the browser tab icon
  • public/ – static files served as-is: public/logo.svg → /logo.svg
  • next.config.ts – Next.js configuration
  • tsconfig.json – TypeScript settings (strict mode, the @/* alias)
  • eslint.config.mjs – lint rules, including Next.js-specific ones
  • AGENTS.md – notes for AI coding assistants pointing to the docs bundled in node_modules/next/dist/docs
  • package.json – dependencies and scripts

As the app grows you'll typically add components/ for shared UI and lib/ for data access and helpers, either at the root or inside a src/ folder. Only folders inside app/ that contain a page.tsx become URLs, so you can keep components next to the pages that use them.

The root layout and home page

Here is a simplified version of the two files every app starts with:

// app/layout.tsx
import type { Metadata } from "next";
import "./globals.css";

export const metadata: Metadata = {
  title: "My Next.js App",
  description: "Built while learning Next.js on LearnFrenzy",
};

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body className="min-h-full p-6">{children}</body>
    </html>
  );
}
// app/page.tsx
export default function Home() {
  return (
    <main>
      <h1 className="text-3xl font-bold">Hello, Next.js!</h1>
      <p>Edit app/page.tsx and save to see your changes.</p>
    </main>
  );
}

Page

Title: My Next.js App
Hello, Next.js!
Edit app/page.tsx and save to see your changes.

The metadata export became the page's <title>. The root layout is required, and it must render <html> and <body> – Next.js doesn't use an index.html file.

next.config.ts

import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  cacheComponents: true,      // the Next.js 16 caching and rendering model ("use cache", static shells)
  partialPrefetching: true,   // prefetch the static part of linked pages
  images: {
    remotePatterns: [new URL("https://images.learnfrenzy.com/**")],   // allow next/image from this host
  },
};

export default nextConfig;

New apps have Cache Components switched on. With it, pages are prerendered as much as possible, data that should be cached is marked with "use cache", and request-specific parts stream in behind <Suspense>. The caching chapter covers it in detail. Many older tutorials describe the previous model (export const revalidate, fetch(…, { cache })), which still exists for apps that don't enable Cache Components.

Scripts

CommandWhat it does
npm run devdevelopment server with Turbopack and Fast Refresh, at localhost:3000
npm run buildproduction build: compiles, type-checks and prerenders every page it can
npm run startruns the production build on a Node.js server
npm run lintESLint with the Next.js rules

Always test the production build

Development mode compiles pages on demand and adds error overlays. Before deploying, run npm run build && npm run start locally: the build fails on type errors, and its route table tells you which pages are static and which are dynamic.

Practice

Try it yourself

  1. Put a site-wide header with the text "LearnFrenzy" into the root layout, above every page.

    Show solution
    // app/layout.tsx
    import "./globals.css";
    
    export default function RootLayout({ children }: { children: React.ReactNode }) {
      return (
        <html lang="en">
          <body>
            <header>LearnFrenzy</header>
            {children}
          </body>
        </html>
      );
    }
    // app/page.tsx
    export default function Home() {
      return <h1>Welcome</h1>;
    }

    Page

    LearnFrenzy
    Welcome

Quick check

Which file wraps every page with <html> and <body>?

app/layout.tsx, the root layout.

Where do you put a file that should be served at /robots.txt as-is?

In public/.

Which command type-checks and prerenders your app?

npm run build.

Summary

  • npx create-next-app@latest app --yes sets up TypeScript, Tailwind, ESLint and the App Router.
  • app/ holds routes; layout.tsx wraps pages; public/ holds static files.
  • Next.js 16 apps start with Cache Components on; test with build + start before deploying.

Finished this lesson?

Mark it complete to track your progress, then carry on with the next lesson.

Next lesson

Search LearnFrenzy

Esc

Quick links