Run this command in your terminal to create a new Next.js project:
npx create-next-app@latest my-portfolioYou’ll be asked a series of questions. Here are the recommended answers:
✔ Would you like to use TypeScript? → Yes
✔ Would you like to use ESLint? → Yes
✔ Would you like to use Tailwind CSS? → Yes
✔ Would you like to use `src/` directory? → No
✔ Would you like to use App Router? → Yes
✔ Would you like to customize the default import alias? → NoTip: Always say Yes to TypeScript and Tailwind. TypeScript catches errors before they happen. Tailwind lets you style directly in your JSX without switching files. Claude handles both of these for you.
After creation, your project looks like this:
my-portfolio/
├── app/
│ ├── layout.tsx ← Root layout (wraps every page)
│ ├── page.tsx ← Home page (localhost:3000)
│ ├── globals.css ← Global styles + Tailwind imports
│ └── favicon.ico ← Browser tab icon
├── public/
│ └── images/ ← Static files (images, fonts, etc.)
├── components/ ← Reusable UI components (you create this)
├── package.json ← Project config + dependencies
├── tailwind.config.ts ← Tailwind customization
├── tsconfig.json ← TypeScript config
├── next.config.js ← Next.js config
└── node_modules/ ← Installed packages (don't touch)In Next.js, the file system is the router. Every page.tsx file inside the app/ directory becomes a URL route automatically.
| File | URL |
|---|---|
app/page.tsx | / |
app/about/page.tsx | /about |
app/projects/page.tsx | /projects |
app/projects/[slug]/page.tsx | /projects/anything |
app/blog/page.tsx | /blog |
To create a new page, create a folder inside app/ and add a page.tsx file:
// app/about/page.tsx
export default function AboutPage() {
return (
<div className="max-w-2xl mx-auto p-8">
<h1 className="text-4xl font-bold mb-4">About Me</h1>
<p className="text-gray-600">
I'm a designer learning to ship with code.
</p>
</div>
)
}Save the file and visit http://localhost:3000/about — your new page is live.
The layout.tsx file wraps every page with shared UI — navigation, footer, global styles. It’s like a frame around your pages.
// app/layout.tsx
import "./globals.css"
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>
<nav className="p-4 border-b">
<a href="/" className="font-bold">My Portfolio</a>
</nav>
{children}
</body>
</html>
)
}Components are functions that return JSX. They live in the components/ folder and can be imported into any page.
// components/Button.tsx
interface ButtonProps {
label: string
variant?: "primary" | "ghost"
onClick?: () => void
}
export function Button({ label, variant = "primary", onClick }: ButtonProps) {
const styles = variant === "primary"
? "bg-gray-900 text-white hover:bg-gray-800"
: "border border-gray-300 text-gray-700 hover:bg-gray-50"
return (
<button
onClick={onClick}
className={`px-4 py-2 rounded-lg font-medium transition-colors ${styles}`}
>
{label}
</button>
)
}Use it in any page:
// app/page.tsx
import { Button } from "@/components/Button"
export default function HomePage() {
return (
<div className="p-8">
<Button label="Click me" variant="primary" />
<Button label="Cancel" variant="ghost" />
</div>
)
}Tip: The
@/alias points to your project root. So@/components/Buttonmeans/components/Button.tsxfrom the project root. This is configured automatically bycreate-next-app.
These commands are defined in package.json and run common tasks:
| Command | What It Does |
|---|---|
npm run dev | Start the development server at localhost:3000 |
npm run build | Build the project for production deployment |
npm start | Run the production build locally |
npm run lint | Check for code quality issues |
npm install | Install all dependencies from package.json |
When you run npm run dev, Next.js watches your files for changes. Every time you save a file, the browser updates automatically — no manual refresh needed. This is called hot reload (or Hot Module Replacement / HMR).
Warning: TypeScript errors can stop hot reload. If your browser stops updating, check the terminal for red error messages. Fix the error, save, and hot reload will resume.
Put images in the public/ folder. Reference them with a path starting from /:
// Using a standard img tag
<img src="/images/hero.jpg" alt="Hero image" />
// Using Next.js Image component (optimized)
import Image from "next/image"
<Image
src="/images/hero.jpg"
alt="Hero image"
width={800}
height={400}
className="rounded-xl"
/>The Next.js Image component automatically optimizes images for performance — lazy loading, responsive sizing, and modern formats.