Web DevelopmentMay 8, 20262 min read21 viewsFeatured

Setting Up Next.js 16 with TypeScript: A Modern Project Walkthrough

Spin up a fresh Next.js 16 project with TypeScript, Tailwind, and a sane folder layout — and understand the App Router conventions before you write your first feature.

A
Admin
Setting Up Next.js 16 with TypeScript: A Modern Project Walkthrough

Next.js 16 is opinionated in ways that pay off if you understand them up front and frustrating if you don't. This walkthrough takes a fresh terminal to a running TypeScript app with Tailwind, the App Router, and the conventions modern Next.js codebases actually use. We'll skip the marketing bullet points and stick to what's worth knowing on day one.

Prerequisites

  • Node.js 18.18 or newer (20+ recommended)
  • A package manager — pnpm, npm, or bun
  • Familiarity with React

Create the project

pnpm create next-app@latest my-app
# Answer:
# - TypeScript? Yes
# - ESLint? Yes
# - Tailwind? Yes
# - src/ directory? Yes
# - App Router? Yes
# - Turbopack? Yes
# - Customize import alias? @/*

cd my-app
pnpm dev

What just got created

  • src/app/ — the App Router. Every folder is a route segment.
  • src/app/layout.tsx — the root layout that wraps every page.
  • src/app/page.tsx — the home page (the URL /).
  • next.config.ts — runtime configuration.
  • tsconfig.json — strict TS, with the @/* import alias mapped to src/*.

Server Components by default

Every component you write in src/app/ is a Server Component unless you opt in to a Client Component with "use client" at the top. Server Components can fetch data directly without an API layer; Client Components are needed for state, effects, and event handlers.

// src/app/page.tsx — Server Component
async function getPosts() {
  const res = await fetch("https://api.example.com/posts", { next: { revalidate: 60 } });
  return res.json();
}

export default async function Home() {
  const posts = await getPosts();
  return <ul>{posts.map((p) => <li key={p.id}>{p.title}</li>)}</ul>;
}

A sane folder layout

src/
  app/                # routes
    layout.tsx
    page.tsx
    blog/
      page.tsx
      [slug]/page.tsx
  components/         # reusable UI
    ui/               # shadcn/ui primitives
    layout/           # header, footer
  lib/                # framework-agnostic code
  db/                 # ORM models, queries

Type-safe environment variables

// src/lib/env.ts
import { z } from "zod";
const Env = z.object({
  DATABASE_URL: z.string().url(),
  NEXT_PUBLIC_SITE_URL: z.string().url(),
});
export const env = Env.parse(process.env);

Tailwind on day one

Tailwind v4 is included by default. Open src/app/globals.css and you'll see the new @import "tailwindcss"; directive plus a small theme block where you can define your tokens. Resist the urge to override everything — start with the defaults and customize only what hurts.

Lint and format

ESLint is wired up with next/core-web-vitals. Add Prettier and an editor integration so format-on-save works. We have a separate tutorial dedicated to the full TypeScript ESLint + Prettier setup.

Where to go next

  • Add an ORM — Drizzle or Prisma sit cleanly inside Server Components.
  • Wire up authentication with NextAuth (Auth.js v5).
  • Deploy to Vercel — vercel from the project root and you're live.
#nextjs#react#typescript#tailwind