Skip to main content

Overview

This portfolio is built with a modern, production-ready tech stack focused on performance, developer experience, and maintainability. Every technology was carefully chosen based on specific requirements and trade-offs.

Core Technologies

Framework & Runtime

{
  "dependencies": {
    "next": "^16.1.5",
    "react": "^19.2.3",
    "react-dom": "^19.2.3"
  }
}
1

Next.js 16.1.5

Why Next.js?
  • Built-in App Router for file-based routing
  • Server Components for optimal performance
  • Automatic code splitting and optimization
  • Built-in image optimization
  • API routes for backend functionality
  • SEO-friendly with SSR/SSG support
  • Excellent developer experience with Turbopack
Key Features Used:
  • App Router architecture
  • Dynamic Open Graph images (opengraph-image.tsx)
  • Dynamic sitemap generation (sitemap.ts)
  • API Routes (api/github/route.ts)
  • Server and Client Components
  • Dynamic imports for code splitting
2

React 19.2.3

Why React 19?
  • Latest features and performance improvements
  • Better concurrent rendering
  • Improved Server Components support
  • Enhanced TypeScript integration
  • Action functions for forms
Features Used:
  • Hooks (useState, useEffect, useMemo, useCallback)
  • Server Components (default in Next.js 16)
  • Client Components ("use client" directive)
  • Dynamic component loading
Version Compatibility Note: React 19 is a major version with breaking changes. Ensure all dependencies are compatible before upgrading existing projects.

Styling & UI

CSS Framework

package.json
{
  "devDependencies": {
    "tailwindcss": "^4",
    "@tailwindcss/postcss": "^4"
  }
}
Why Tailwind CSS 4?
  • Utility-first CSS for rapid development
  • Zero runtime overhead (styles extracted at build time)
  • Excellent tree-shaking (unused styles removed)
  • Custom design system via CSS variables
  • JIT compiler for instant compilation
  • New PostCSS-based architecture in v4
Configuration:
  • Custom color scheme using CSS variables
  • Font family with Geist Sans & Geist Mono
  • Responsive breakpoints
  • Dark mode support via CSS variables

Component Libraries

{
  "dependencies": {
    "@radix-ui/react-dialog": "^1.1.15",
    "@radix-ui/react-dropdown-menu": "^2.1.15",
    "@radix-ui/react-label": "^2.1.7",
    "@radix-ui/react-slot": "^1.2.3",
    "radix-ui": "^1.4.3"
  }
}
1

Radix UI

Why Radix UI?
  • Unstyled, accessible components
  • WAI-ARIA compliant
  • Keyboard navigation built-in
  • Focus management
  • Highly customizable
  • Works perfectly with Tailwind CSS
Components Used:
  • Dialog (modals)
  • Dropdown Menu (navigation)
  • Label (form labels)
  • Slot (polymorphic components)
2

shadcn/ui Pattern

Why shadcn/ui?
  • Not a library, but a collection of copy-paste components
  • Full ownership of component code
  • Built on Radix UI + Tailwind CSS
  • TypeScript-first
  • Customizable without fighting abstractions
Implementation:
  • Components live in src/components/ui/
  • Configured via components.json
  • Custom variants using class-variance-authority

Utility Libraries

{
  "dependencies": {
    "class-variance-authority": "^0.7.1",
    "clsx": "^2.1.1",
    "tailwind-merge": "^3.3.0"
  }
}
LibraryPurposeUsage
clsxConditional className constructionclsx({ 'bg-red': error })
tailwind-mergeMerge Tailwind classes without conflictstwMerge('p-4', 'p-2')p-2
class-variance-authorityType-safe component variantsButton sizes/variants
Combined Utility:
// src/utils/cn.ts
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}

Animation & Interactions

{
  "dependencies": {
    "framer-motion": "^12.17.0"
  }
}

Framer Motion

Why Framer Motion?
  • Declarative animation API
  • Spring physics for natural motion
  • Gesture recognition (drag, tap, hover)
  • Layout animations
  • Scroll-triggered animations
  • Excellent TypeScript support
  • Production-optimized performance
Features Used:
  • Page transitions
  • Scroll animations
  • Hover effects
  • Drag interactions (use-drag-scroll.ts)
  • Animated number counters
  • Stagger animations for lists
Framer Motion’s motion components are tree-shakeable. Only import the components you use to keep bundle size small.

Forms & Validation

{
  "dependencies": {
    "react-hook-form": "^7.57.0",
    "@hookform/resolvers": "^5.1.1",
    "zod": "^3.25.58"
  }
}
1

React Hook Form

Why React Hook Form?
  • Minimal re-renders (uncontrolled forms)
  • Built-in validation
  • Small bundle size (~9KB)
  • Excellent TypeScript support
  • Easy integration with UI libraries
Used In:
  • Contact form (src/components/contact.tsx)
  • Form field management
  • Error handling
2

Zod

Why Zod?
  • TypeScript-first schema validation
  • Runtime type checking
  • Automatic type inference
  • Great error messages
  • Composable schemas
Integration:
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";

const schema = z.object({
  email: z.string().email(),
  message: z.string().min(10)
});

const form = useForm({
  resolver: zodResolver(schema)
});

State Management

{
  "dependencies": {
    "zustand": "^5.0.11"
  }
}

Zustand

Why Zustand over Redux/Context?
  • ✅ Minimal boilerplate (no providers, actions, reducers)
  • ✅ Small bundle size (~1KB)
  • ✅ No Context Provider hell
  • ✅ Built-in TypeScript support
  • ✅ Middleware support (persist, devtools)
  • ✅ Works seamlessly with React 19
Alternatives Considered:
  • Redux: Too much boilerplate for simple state
  • Context API: Performance issues with frequent updates
  • Jotai: Good, but Zustand has better DX for this use case
  • Recoil: Meta library with uncertain future
Implementation: See State Management for detailed usage.

Icons

{
  "dependencies": {
    "lucide-react": "^0.514.0",
    "react-icons": "^5.5.0"
  }
}
Lucide React (Primary)
  • Modern, consistent icon set
  • Tree-shakeable (only import icons you use)
  • Customizable size, color, stroke
  • 1000+ icons
React Icons (Secondary)
  • Access to multiple icon sets (Font Awesome, Material, etc.)
  • Social media icons
  • Brand logos
  • Fallback for icons not in Lucide
Usage:
import { Github, Mail, Linkedin } from "lucide-react";
import { SiTypescript, SiReact } from "react-icons/si";

<Github size={24} strokeWidth={1.5} />
<SiTypescript className="text-blue-500" />

Notifications

{
  "dependencies": {
    "sonner": "^2.0.5"
  }
}

Sonner

Why Sonner?
  • Beautiful, opinionated toast notifications
  • Stacking behavior out of the box
  • Promise-based toasts for async operations
  • Keyboard accessible
  • Dark mode support
  • Minimal setup required
Usage:
import { toast } from "sonner";

toast.success("Message sent!");
toast.error("Something went wrong");
toast.promise(sendEmail(), {
  loading: "Sending...",
  success: "Sent!",
  error: "Failed"
});

Development Tools

TypeScript

{
  "devDependencies": {
    "typescript": "^5",
    "@types/node": "^20",
    "@types/react": "^19",
    "@types/react-dom": "^19"
  }
}
Configuration Highlights:
  • Strict mode enabled (strict: true)
  • Path aliases (@/*)
  • JSX: react-jsx (React 19 new JSX transform)
  • Target: ES2017 (broad browser support)

Code Quality

{
  "devDependencies": {
    "eslint": "^9",
    "eslint-config-next": "15.3.3",
    "eslint-config-prettier": "^10.1.8",
    "prettier": "^3.6.2",
    "@eslint/eslintrc": "^3"
  }
}
1

ESLint

Configuration:
  • Next.js recommended rules
  • Prettier integration (no conflicts)
  • React Hooks rules
  • Accessibility checks
Commands:
npm run lint        # Check for errors
npm run lint --fix  # Auto-fix issues
2

Prettier

Configuration (.prettierrc):
{
  "semi": true,
  "trailingComma": "none",
  "singleQuote": false,
  "printWidth": 100,
  "tabWidth": 2
}
Commands:
npm run format     # Format all files

Build Tools & Optimization

{
  "dependencies": {
    "@next/bundle-analyzer": "^16.1.1",
    "cross-env": "^10.1.0"
  },
  "scripts": {
    "dev": "next dev --turbopack",
    "build": "next build",
    "start": "next start"
  }
}

Build Features

ToolPurposeBenefits
TurbopackNext.js bundler (beta)700x faster than Webpack
Bundle AnalyzerVisualize bundle sizeIdentify optimization opportunities
cross-envCross-platform env varsWorks on Windows/Mac/Linux
Analyze Bundle:
ANALYZE=true npm run build

Performance Optimizations

  1. Image Optimization
    • WebP format for all images
    • Next.js Image component with lazy loading
    • Cloudinary remote pattern for external images
  2. Code Splitting
    • Dynamic imports for heavy components
    • Route-based splitting (automatic with App Router)
    • Lazy-loaded sections on home page
  3. Font Optimization
    • Self-hosted Google Fonts (Geist Sans & Mono)
    • Font display: swap
    • Variable fonts for size reduction
  4. Bundle Size
    • Tree-shaking enabled
    • Import only needed icons
    • No moment.js (using native Date)
    • Minimal dependencies
  5. Caching
    • Static generation where possible
    • LocalStorage for user preferences
    • Service worker ready (PWA potential)

Version Compatibility Matrix

PackageVersionCompatible With
Next.js16.1.5React 19+
React19.2.3Next.js 15+
Tailwind CSS4.xPostCSS 8+
TypeScript5.xNext.js 15+
Framer Motion12.xReact 18-19
Zustand5.xReact 18-19
React Hook Form7.xReact 16.8+
Zod3.xTypeScript 4.5+
Breaking Changes in React 19:
  • New JSX transform (automatic runtime)
  • Stricter hooks rules
  • Removed legacy context
  • Server Components changes
Ensure all dependencies are compatible before upgrading.

Why Not…?

Why not Vue/Svelte?
  • React has the largest ecosystem and job market
  • Next.js is the industry standard for React SSR
  • Better TypeScript integration
Why not Remix?
  • Next.js has more mature App Router
  • Better build tooling (Turbopack)
  • Larger community and resources
Why not Astro?
  • Need more dynamic interactivity
  • Zustand state management works better with React
  • Component islands not needed for this use case
Why not styled-components/Emotion?
  • Tailwind CSS has better performance (no runtime)
  • Easier to maintain with utility classes
  • Better tree-shaking
Why not Redux?
  • Zustand is simpler for this scale
  • Less boilerplate
  • Better performance for small apps
Why not SWR/React Query?
  • Minimal data fetching needs
  • Static content from JSON files
  • GitHub API called server-side only

Future Considerations

Technologies being considered for future additions:
  • Vitest: Fast unit testing (replacing Jest)
  • Playwright: E2E testing
  • tRPC: Type-safe API calls (if backend grows)
  • TanStack Query: If more data fetching is needed
  • Storybook: Component documentation

Quick Reference

Install All Dependencies

npm install

Development

npm run dev          # Start dev server with Turbopack
npm run build        # Production build
npm run start        # Start production server
npm run lint         # Run ESLint
npm run format       # Format with Prettier

Dependency Categories

  • Framework: Next.js 16, React 19
  • Styling: Tailwind CSS 4, Radix UI
  • State: Zustand
  • Forms: React Hook Form + Zod
  • Animation: Framer Motion
  • Icons: Lucide React, React Icons
  • Notifications: Sonner
  • Dev Tools: TypeScript, ESLint, Prettier
See Project Structure for file organization and State Management for Zustand implementation.

Build docs developers (and LLMs) love