Building a Modern Portfolio with Next.js and Tailwind CSS
A step-by-step guide to creating a stunning portfolio website using Next.js 15, Tailwind CSS v4, and modern web development best practices.
Creating a portfolio website is essential for showcasing your work and skills. In this tutorial, we'll build a modern, responsive portfolio using Next.js 15 and Tailwind CSS v4.
Why Next.js and Tailwind?
Next.js and Tailwind CSS are a powerful combination for building modern web applications:
- Next.js: React framework with server-side rendering, routing, and optimization
- Tailwind CSS: Utility-first CSS framework for rapid UI development
- Performance: Built-in optimizations for images, fonts, and code splitting
- Developer Experience: Hot reloading, TypeScript support, and great tooling
Project Setup
Let's start by creating a new Next.js project:
npx create-next-app@latest my-portfolio
cd my-portfolio
npm run dev
When prompted, select these options:
- TypeScript: Yes
- ESLint: Yes
- Tailwind CSS: Yes
- App Router: Yes
Project Structure
Here's the recommended folder structure:
my-portfolio/
├── src/
│ ├── app/
│ │ ├── page.tsx
│ │ ├── layout.tsx
│ │ └── globals.css
│ ├── components/
│ │ ├── Header.tsx
│ │ ├── Hero.tsx
│ │ ├── Projects.tsx
│ │ └── Footer.tsx
│ └── data/
│ └── projects.ts
├── public/
│ └── images/
└── package.json
Creating the Hero Section
The hero section is the first thing visitors see. Let's make it impactful:
export function Hero() {
return (
<section className="flex min-h-screen items-center justify-center bg-gradient-to-br from-neutral-50 to-neutral-100 dark:from-neutral-950 dark:to-neutral-900">
<div className="mx-auto max-w-4xl px-6 text-center">
<h1 className="mb-6 bg-gradient-to-r from-neutral-900 to-neutral-600 bg-clip-text text-5xl font-bold text-transparent md:text-7xl dark:from-neutral-100 dark:to-neutral-400">
Hi, I'm Your Name
</h1>
<p className="mb-8 text-xl text-neutral-600 md:text-2xl dark:text-neutral-400">
Full Stack Developer & UI/UX Enthusiast
</p>
<div className="flex justify-center gap-4">
<button className="rounded-lg bg-neutral-900 px-6 py-3 text-white transition hover:bg-neutral-800">
View Projects
</button>
<button className="rounded-lg border border-neutral-300 px-6 py-3 transition hover:bg-neutral-50">
Contact Me
</button>
</div>
</div>
</section>
);
}
Dark Mode Support
Tailwind CSS v4 makes dark mode implementation straightforward. Add the theme provider:
import { ThemeProvider } from "next-themes";
export function Providers({ children }: { children: React.ReactNode }) {
return (
<ThemeProvider attribute="class" defaultTheme="system">
{children}
</ThemeProvider>
);
}
Then wrap your app in layout.tsx:
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}
Projects Section
Display your work with a clean grid layout:
const projects = [
{
title: "E-commerce Platform",
description: "A full-stack e-commerce solution with Next.js and Stripe",
image: "/images/project1.jpg",
tags: ["Next.js", "TypeScript", "Stripe"],
link: "https://example.com",
},
// More projects...
];
export function Projects() {
return (
<section className="px-6 py-20">
<h2 className="mb-12 text-center text-4xl font-bold">
Featured Projects
</h2>
<div className="mx-auto grid max-w-7xl gap-8 md:grid-cols-2 lg:grid-cols-3">
{projects.map((project) => (
<div
key={project.title}
className="overflow-hidden rounded-lg border transition hover:shadow-lg"
>
<img
src={project.image}
alt={project.title}
className="h-48 w-full object-cover"
/>
<div className="p-6">
<h3 className="mb-2 text-xl font-semibold">{project.title}</h3>
<p className="mb-4 text-neutral-600 dark:text-neutral-400">
{project.description}
</p>
<div className="flex flex-wrap gap-2">
{project.tags.map((tag) => (
<span
key={tag}
className="rounded-full bg-neutral-100 px-3 py-1 text-sm dark:bg-neutral-800"
>
{tag}
</span>
))}
</div>
</div>
</div>
))}
</div>
</section>
);
}
Performance Optimization
Image Optimization
Use Next.js Image component for automatic optimization:
import Image from "next/image";
<Image
src="/images/project.jpg"
alt="Project"
width={800}
height={600}
className="rounded-lg"
priority
/>;
Font Optimization
Next.js 15 includes automatic font optimization:
import { Inter } from "next/font/google";
const inter = Inter({ subsets: ["latin"] });
export default function RootLayout({ children }) {
return (
<html lang="en" className={inter.className}>
<body>{children}</body>
</html>
);
}
Deployment
Deploy your portfolio to Vercel with these steps:
- Push your code to GitHub
- Import your repository on Vercel
- Configure build settings (usually auto-detected)
- Deploy!
Your portfolio will be live at your-project.vercel.app.
Best Practices
Here are some tips for a great portfolio:
- Keep it simple - Focus on your best work
- Make it fast - Optimize images and code
- Mobile-first - Ensure responsive design
- Add analytics - Track visitor behavior
- Update regularly - Keep content fresh
Conclusion
You now have a modern, performant portfolio built with Next.js and Tailwind CSS. The combination of these technologies provides:
- Fast performance with server-side rendering
- Beautiful UI with utility-first CSS
- Great SEO with Next.js metadata API
- Easy deployment with Vercel
Start building your portfolio today and showcase your amazing work to the world!
Happy coding! 🚀