23 NextJS Portfolio Template Examples For Design Inspiration

Explore the best NextJS portfolio templates and examples to showcase your work professionally and stand out from the competition.

November 28, 202417 min read

Your portfolio is often the first impression potential clients or employers have of your work. In today's competitive landscape, having a well-designed, fast, and responsive portfolio website is crucial for standing out.

Portfolio Website Design

Why Choose NextJS for Your Portfolio?

NextJS offers several advantages for portfolio websites:

  • Performance: Built-in optimization and static generation
  • SEO: Server-side rendering for better search visibility
  • Developer Experience: Hot reload, TypeScript support, and modern tooling
  • Flexibility: Can be deployed anywhere and scales easily

Essential Portfolio Sections

Hero Section

Your hero section should immediately communicate who you are and what you do.

export default function Hero() {
  return (
    <section className="min-h-screen flex items-center justify-center">
      <div className="text-center space-y-6">
        <h1 className="text-4xl md:text-6xl font-bold">
          Hi, I'm <span className="text-blue-600">John Doe</span>
        </h1>
        <p className="text-xl text-gray-600 max-w-2xl mx-auto">
          Full-stack developer passionate about creating beautiful, functional
          web experiences
        </p>
        <div className="flex gap-4 justify-center">
          <Button variant="primary">View My Work</Button>
          <Button variant="outline">Contact Me</Button>
        </div>
      </div>
    </section>
  );
}

Project Showcase

Display your best work with engaging visuals and clear descriptions.

interface Project {
  id: string;
  title: string;
  description: string;
  image: string;
  technologies: string[];
  liveUrl?: string;
  githubUrl?: string;
}

export default function ProjectGrid({ projects }: { projects: Project[] }) {
  return (
    <div className="grid md:grid-cols-2 lg:grid-cols-3 gap-8">
      {projects.map((project) => (
        <div
          key={project.id}
          className="group relative overflow-hidden rounded-lg"
        >
          <img
            src={project.image}
            alt={project.title}
            className="w-full h-48 object-cover transition-transform group-hover:scale-105"
          />
          <div className="absolute inset-0 bg-gradient-to-t from-black/80 to-transparent opacity-0 group-hover:opacity-100 transition-opacity">
            <div className="absolute bottom-4 left-4 right-4">
              <h3 className="text-white font-semibold">{project.title}</h3>
              <p className="text-gray-200 text-sm">{project.description}</p>
            </div>
          </div>
        </div>
      ))}
    </div>
  );
}

Minimalist Layouts

Clean, focused designs that put your work front and center:

  • Generous white space
  • Typography-first approach
  • Subtle animations and transitions
  • Limited color palettes

Interactive Elements

Engage visitors with interactive components:

import { useState } from "react";

export default function InteractiveSkillBar() {
  const [hoveredSkill, setHoveredSkill] = useState<string | null>(null);

  const skills = [
    { name: "React", level: 90 },
    { name: "TypeScript", level: 85 },
    { name: "NextJS", level: 88 },
  ];

  return (
    <div className="space-y-4">
      {skills.map((skill) => (
        <div
          key={skill.name}
          onMouseEnter={() => setHoveredSkill(skill.name)}
          onMouseLeave={() => setHoveredSkill(null)}
          className="relative"
        >
          <div className="flex justify-between mb-1">
            <span className="font-medium">{skill.name}</span>
            <span className="text-sm text-gray-600">{skill.level}%</span>
          </div>
          <div className="w-full bg-gray-200 rounded-full h-2">
            <div
              className="bg-blue-600 h-2 rounded-full transition-all duration-700 ease-out"
              style={{
                width: hoveredSkill === skill.name ? `${skill.level}%` : "0%",
              }}
            />
          </div>
        </div>
      ))}
    </div>
  );
}

Dark Mode Support

Implement dark mode for better user experience:

"use client";

import { useTheme } from "next-themes";
import { useState, useEffect } from "react";

export default function ThemeToggle() {
  const [mounted, setMounted] = useState(false);
  const { theme, setTheme } = useTheme();

  useEffect(() => {
    setMounted(true);
  }, []);

  if (!mounted) {
    return null;
  }

  return (
    <button
      onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
      className="p-2 rounded-lg bg-gray-200 dark:bg-gray-800"
    >
      {theme === "dark" ? "☀️" : "🌙"}
    </button>
  );
}

Performance Optimization

Image Optimization

Use NextJS Image component for optimal loading:

import Image from "next/image";

export default function OptimizedPortfolioImage() {
  return (
    <Image
      src="/project-screenshot.jpg"
      alt="Project Screenshot"
      width={600}
      height={400}
      placeholder="blur"
      blurDataURL="data:image/jpeg;base64,..."
      className="rounded-lg"
    />
  );
}

Static Generation

Pre-generate pages for better performance:

export async function getStaticProps() {
  const projects = await getProjects();

  return {
    props: {
      projects,
    },
    revalidate: 3600, // Revalidate every hour
  };
}

SEO Best Practices

Meta Tags

import Head from "next/head";

export default function Portfolio() {
  return (
    <>
      <Head>
        <title>John Doe - Full Stack Developer</title>
        <meta
          name="description"
          content="Portfolio of John Doe, a full-stack developer specializing in React and NextJS"
        />
        <meta property="og:title" content="John Doe - Full Stack Developer" />
        <meta
          property="og:description"
          content="Portfolio showcasing modern web development projects"
        />
        <meta property="og:image" content="/og-image.jpg" />
        <meta name="twitter:card" content="summary_large_image" />
      </Head>
      {/* Your portfolio content */}
    </>
  );
}

Structured Data

Add JSON-LD structured data for better search visibility:

const portfolioSchema = {
  "@context": "https://schema.org",
  "@type": "Person",
  name: "John Doe",
  jobTitle: "Full Stack Developer",
  url: "https://johndoe.dev",
  sameAs: ["https://github.com/johndoe", "https://linkedin.com/in/johndoe"],
};

export default function Portfolio() {
  return (
    <>
      <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(portfolioSchema) }}
      />
      {/* Your content */}
    </>
  );
}

Conclusion

Creating an effective NextJS portfolio requires thoughtful planning, clean design, and optimal performance. Focus on showcasing your best work, ensuring fast load times, and providing a great user experience across all devices.

Remember to regularly update your portfolio with new projects and keep your content fresh and relevant to your target audience.