Change Theme Color
Next.js· 12 min read

How I Built My Production-Ready Next.js Portfolio — Moataseem Shaaban

Moataseem Shaaban walks through how he built, optimized, and deployed his portfolio website using Next.js 15, Tailwind CSS v4, GSAP animations, and a hardened VPS. A full guide from setup to 100/100 PageSpeed.

MS

Moataseem Shaaban

Full Stack Developer & Software Engineer

I'm Moataseem Shaaban, a full stack developer based in Cairo, Egypt. When I decided to rebuild my portfolio from scratch, I wanted it to be more than a pretty page — I wanted it to be a showcase of real engineering. In this post, I'll walk you through exactly how I built moataseem.com using Next.js 15, Tailwind CSS v4, GSAP, and deployed it on my own hardened Ubuntu VPS.

Why I Chose Next.js for My Portfolio

As a full stack developer who works with React daily, Next.js was the natural choice for my portfolio at moataseem.com. With features like static export, automatic code splitting, and built-in image optimization, it gives you everything you need to build a fast, SEO-friendly portfolio.

For my portfolio specifically, I used the static export feature (output: 'export'). It generates plain HTML, CSS, and JavaScript files that I serve from my own Nginx server — no Node.js runtime required in production.

Key Advantages

  • Static Generation: Pre-renders every page at build time, resulting in instant load times
  • Automatic Code Splitting: Only loads the JavaScript needed for each page
  • Built-in SEO Support: The Metadata API makes it trivial to add Open Graph tags, Twitter cards, and structured data
  • React 19 Support: Server Components, improved hydration, and better performance out of the box

Project Setup and Architecture

Start by creating a new Next.js project with the App Router:

bash
npx create-next-app@latest portfolio --app --tailwind --eslint

I recommend organizing your project like this:

src/
├── app/
│   ├── layout.jsx        # Root layout with metadata
│   ├── page.jsx           # Home page
│   └── blog/
│       ├── page.jsx       # Blog listing
│       └── [slug]/
│           └── page.jsx   # Individual posts
├── components/            # Reusable UI components
├── common/
│   └── constants/         # Metadata, blog data
├── hooks/                 # Custom React hooks
├── lib/                   # Utility functions
└── assets/                # Images, fonts

This structure separates concerns cleanly and scales well as your portfolio grows.

How I Styled It with Tailwind CSS v4

For moataseem.com, I went with Tailwind CSS v4 — the ground-up rewrite with a Rust-based engine. The new @theme directive lets you define design tokens directly in CSS, which I found much cleaner than the old config file approach:

css
@import "tailwindcss";

@theme inline {
  --color-primary: oklch(0.7 0.15 160);
  --color-background: oklch(0.145 0 0);
  --color-foreground: oklch(0.985 0 0);
  --radius: 0.625rem;
}

The OKLCH color space is perceptually uniform, meaning colors look consistent across different hues and lightness levels. This is a significant upgrade over HSL for building cohesive color palettes.

My Dynamic Theme Selector

One feature I'm proud of on moataseem.com is the dynamic color theme selector — visitors can choose their preferred accent color and it persists across visits. The trick is using CSS custom properties that can be updated at runtime:

javascript
document.documentElement.style.setProperty('--color-primary', newColor);
localStorage.setItem('portfolio-theme', themeName);

This approach gives you theme persistence without any server-side logic.

How Moataseem Shaaban Uses GSAP for Portfolio Animations

Animations make or break a portfolio's first impression. On moataseem.com, I use GSAP (GreenSock Animation Platform) for all complex animations because it outperforms CSS animations in control and cross-browser consistency.

Key animation patterns I built for my portfolio:

  • Entrance animations: Elements fade in and slide up as sections enter the viewport using ScrollTrigger
  • Parallax effects: Background elements move at different speeds based on scroll position
  • Magnetic cursor: Interactive elements that subtly attract toward the cursor on hover
  • Staggered reveals: Lists and grids animate item by item for a polished feel
javascript
gsap.registerPlugin(ScrollTrigger);

gsap.from('.section-title', {
  y: 60,
  opacity: 0,
  duration: 1,
  scrollTrigger: {
    trigger: '.section-title',
    start: 'top 80%',
  }
});

SEO Optimization

For a portfolio, SEO is critical. Here's a comprehensive checklist:

Metadata API

Next.js 15's Metadata API is powerful. Define your metadata in a constants file and import it:

javascript
export const metadata = {
  title: 'Your Name — Full Stack Developer',
  description: 'Your compelling description here',
  metadataBase: new URL('https://yourdomain.com'),
  alternates: { canonical: '/' },
  openGraph: {
    title: 'Your Name — Portfolio',
    images: [{ url: '/og-image.png', width: 1200, height: 630 }],
  },
};

Structured Data (JSON-LD)

Add Person, WebSite, and ProfilePage schemas to help search engines understand your content:

jsx
<script type="application/ld+json">
  {JSON.stringify({
    "@context": "https://schema.org",
    "@type": "Person",
    "name": "Your Name",
    "jobTitle": "Full Stack Developer",
    "url": "https://yourdomain.com",
    "knowsAbout": ["React", "Next.js", "Node.js"]
  })}
</script>

Technical SEO Checklist

  1. 1.Canonical URLs — Prevent duplicate content issues
  2. 2.robots.txt — Allow crawlers and reference your sitemap
  3. 3.sitemap.xml — List all your pages with last modified dates
  4. 4.HSTS headers — Signal trust to search engines
  5. 5.Core Web Vitals — Optimize LCP, FID, and CLS scores
  6. 6.Mobile-first — Google uses mobile-first indexing

Deployment on a VPS

While platforms like Vercel are convenient, deploying on your own VPS gives you full control over performance tuning:

  1. 1.Build locally: npm run build generates static files in the out/ directory
  2. 2.Upload to server: Use rsync to sync files to your web root
  3. 3.Nginx configuration: Serve static files with aggressive caching
  4. 4.SSL with Certbot: Free HTTPS certificates from Let's Encrypt
  5. 5.Gzip compression: Reduce file sizes by 60-80%

Nginx Performance Config

nginx
location /_next/static/ {
    expires 1y;
    add_header Cache-Control "public, immutable";
}

location ~* \.(jpg|jpeg|png|gif|ico|svg|webp|woff|woff2)$ {
    expires 1y;
    add_header Cache-Control "public, no-transform";
}

Performance Results on moataseem.com

With this setup, my portfolio at moataseem.com achieves:

  • PageSpeed Score: 100/100 on both mobile and desktop
  • First Contentful Paint: Under 0.5 seconds
  • Largest Contentful Paint: Under 1.2 seconds
  • Total Blocking Time: 0ms
  • Cumulative Layout Shift: 0

Conclusion — Moataseem Shaaban's Approach to Portfolio Engineering

Building my portfolio at moataseem.com taught me that a great developer portfolio is about balancing aesthetics with engineering. I used Next.js for the framework, Tailwind CSS v4 for styling, GSAP for animations, and deployed on my own hardened VPS for full control.

If you're a developer building your own portfolio, focus on performance and SEO from day one — they're not afterthoughts, they're requirements. The source code for my portfolio is open source on GitHub. Feel free to use it as a reference.

I'm Moataseem Shaaban — if you have questions about this build or want to collaborate, reach out through my contact page.

MS
Loading0%
Initializing portfolio...