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.
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:
npx create-next-app@latest portfolio --app --tailwind --eslintI 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, fontsThis 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:
@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:
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
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:
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:
<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.Canonical URLs — Prevent duplicate content issues
- 2.robots.txt — Allow crawlers and reference your sitemap
- 3.sitemap.xml — List all your pages with last modified dates
- 4.HSTS headers — Signal trust to search engines
- 5.Core Web Vitals — Optimize LCP, FID, and CLS scores
- 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.Build locally:
npm run buildgenerates static files in theout/directory - 2.Upload to server: Use
rsyncto sync files to your web root - 3.Nginx configuration: Serve static files with aggressive caching
- 4.SSL with Certbot: Free HTTPS certificates from Let's Encrypt
- 5.Gzip compression: Reduce file sizes by 60-80%
Nginx Performance Config
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.