Open Source Portfolio Template: Setup Guide
Fork it, change one config file, deploy. A complete guide to setting up this Next.js 16 portfolio template with MDX blog, feature flags, and API integrations.
Why I open-sourced this
I spent months building this portfolio. The animations, the content system, the feature flags. After shipping it, I realized every developer faces the same struggle: spending weeks on a portfolio instead of building real projects.
So I turned it into a template.
Fork the repo. Edit one config file. Deploy. Your portfolio is live in under 10 minutes.
This guide walks you through every step.
What you get
This template ships with:
- Next.js 16 with App Router and Turbopack
- React 19 with Server Components
- Tailwind CSS v4 with custom design tokens
- MDX blog powered by Velite (type-safe content at build time)
- Framer Motion animations with 15 toggleable feature flags
- GitHub contributions calendar
- Spotify "Now Playing" widget
- WakaTime coding stats
- Contact form with webhook or email delivery
- Full SEO setup: meta tags, Open Graph, structured data, sitemap, robots.txt
- llms.txt routes for AI discoverability
- 4 easter eggs (Konami code, matrix rain, logo secret, console greeting)
Everything is configurable. Everything is optional.
Quick start
Requirements
- Node.js 18.17 or later
- npm, pnpm, or yarn
4 commands to get running
git clone https://github.com/karanjot786/portfolio.git
cd portfolio
npm install
npm run devOpen http://localhost:3000. You should see the site running with placeholder content.
Step 1: Make it yours
Open config/site.config.ts. This single file controls your name, bio, links, and stats across the entire site.
export const siteConfig = {
name: "Your Name",
title: "Your Name | Full Stack Developer",
tagline: "Your tagline here.",
description: "A short bio for meta descriptions.",
url: "https://yoursite.com",
author: {
name: "Your Name",
email: "you@email.com",
avatar: "/images/avatar.png",
bio: {
short: "One-line bio for cards and previews.",
long: "Detailed bio for the about section."
},
location: {
city: "Your City",
country: "Your Country",
timezone: "UTC+0"
}
},
social: {
github: "https://github.com/yourusername",
twitter: "https://x.com/yourusername",
linkedin: "https://linkedin.com/in/yourusername",
email: "you@email.com"
},
stats: {
yearsOfExperience: 3,
projectsCompleted: 10,
githubContributions: 500,
linesOfCode: "20K+"
}
};Replace the placeholder values. Save. The entire site updates.
Add your photo
Drop your photo into public/images/ as avatar.png. The about section and metadata pick it up automatically.
Step 2: Set up environment variables
Copy the example file:
cp .env.example .env.localHere is what each variable does:
Required for production
NEXT_PUBLIC_SITE_URL=https://yoursite.comGitHub calendar (optional)
GITHUB_TOKEN=ghp_your_token_here
GITHUB_USERNAME=yourusernameGenerate a GitHub token at github.com/settings/tokens with the read:user scope. The contributions calendar shows your coding activity on the homepage.
Spotify widget (optional)
SPOTIFY_CLIENT_ID=your_client_id
SPOTIFY_CLIENT_SECRET=your_client_secret
SPOTIFY_REFRESH_TOKEN=your_refresh_tokenCreate a Spotify app at developer.spotify.com/dashboard. The widget shows what you are listening to in real time.
WakaTime stats (optional)
WAKATIME_API_KEY=your_api_keyGet your API key at wakatime.com/settings/api-key. The widget displays your weekly coding time broken down by language.
Contact form (pick one)
Option A: Webhook delivery
CONTACT_WEBHOOK_URL=https://hooks.slack.com/your-webhookOption B: Email via Resend
RESEND_API_KEY=re_your_key
CONTACT_TO_EMAIL=you@email.comSkip the API keys you do not need. The site works fine without them. Features with missing keys hide themselves.
Step 3: Add your experience
Open config/data/experience.ts. Each entry follows this structure:
{
id: "1",
company: "Acme Corp",
companyUrl: "https://acme.com",
role: "Senior Developer",
location: "Remote",
startDate: "2024-01",
endDate: "2025-06",
current: false,
description: "Built the payment infrastructure.",
highlights: [
"Reduced checkout latency by 40%",
"Migrated 2M users to new auth system"
],
technologies: [
{ name: "React", icon: SiReact, color: "#61DAFB" },
{ name: "Node.js", icon: SiNodedotjs, color: "#339933" }
]
}Set current: true for your active position. The timeline renders in order.
Update your skills
Open config/data/skills.ts. Skills are grouped by category:
{
category: "Frontend",
skills: [
{
name: "React",
icon: SiReact,
color: "#61DAFB",
proficiency: 90,
yearsOfExperience: 4,
featured: true
}
]
}Skills marked featured: true appear in the hero section.
Step 4: Add projects
Create a new file in content/projects/. Name it your-project.mdx.
---
title: "Your Project Name"
description: "One-line description."
publishedAt: "2025-06-01"
featured: true
status: "active"
categories: ["Web", "SaaS"]
techStack: ["React", "Python", "Docker"]
github: "https://github.com/you/project"
liveUrl: "https://project.com"
metrics:
users: "5,000 active"
performance: "99.9% uptime"
---
Write your project description here in Markdown.
Include screenshots, architecture decisions, or lessons learned.The techStack array maps to icons automatically. If your tech is not in the mapping, add one line to lib/tech-icons.ts:
"Vue.js": { icon: SiVuedotjs, color: "#4FC08D" },40+ technologies are pre-mapped. You likely will not need to add anything.
Step 5: Write blog posts
Create a new file in content/blog/. Name it your-post.mdx.
---
title: "Your Blog Post Title"
excerpt: "A short summary for previews and SEO."
publishedAt: "2025-06-15"
featured: false
tags: ["React", "Tutorial"]
categories: ["Web Development"]
---
Your content goes here. Write in standard Markdown.Code blocks get syntax highlighting with the github-dark theme automatically. Headings generate anchor links for deep linking.
The blog supports:
- Frontmatter validation at build time (misspell a field and the build fails)
- Auto-generated reading time
- Tag and category filtering
- RSS feed at
/blog/rss - Related posts based on shared tags
Step 6: Toggle features
Open config/features.config.ts. Every visual effect and integration has a boolean switch:
export const featuresConfig = {
// 3D effects
hero3D: true,
particleField: true,
floatingShapes: true,
// Cursor effects
customCursor: true,
cursorTrail: true,
// Scroll effects
velocitySkew: true,
scrollProgress: true,
magneticButtons: true,
// API integrations
githubCalendar: true,
spotifyNowPlaying: true,
wakatimeStats: true,
// Blog features
readingProgress: true,
tableOfContents: true,
codeHighlight: true,
// Easter eggs
konamiCode: true,
consoleGreeting: true,
// Analytics
vercelAnalytics: false,
};Set any flag to false. That feature ships zero JavaScript. The site code-splits everything through next/dynamic, so disabled features do not affect your bundle size.
Testing on a lower-end device? Disable cursorTrail, velocitySkew, and hero3D. The site stays fast.
Step 7: SEO configuration
Open config/seo.config.ts:
export const seoConfig = {
defaultTitle: "Your Name | Developer",
defaultDescription: "Your meta description.",
keywords: ["your", "keywords", "here"],
language: "en",
openGraph: {
type: "website",
locale: "en_US",
siteName: "Your Name",
images: [{
url: "https://yoursite.com/images/og/og-default.jpg",
width: 1200,
height: 630,
alt: "Your Name"
}]
},
twitter: {
handle: "@yourusername",
cardType: "summary_large_image"
},
structuredData: {
person: {
name: "Your Name",
jobTitle: "Full Stack Developer",
url: "https://yoursite.com",
sameAs: [
"https://github.com/yourusername",
"https://linkedin.com/in/yourusername"
]
}
}
};The template generates robots.txt, sitemap.xml, and JSON-LD structured data from this config. No plugins or extra setup needed.
AI discoverability
The template includes an app/(llms)/ route group that serves structured text at /llms.txt and /llms-full.txt. AI crawlers from ChatGPT, Perplexity, and Claude pick up this content. You do not need to configure anything. The routes generate from your existing content automatically.
Step 8: Customize the theme
Open config/theme.config.ts:
export const themeConfig = {
colors: {
primary: "#00ffff",
accent: "#00ffff"
},
fonts: {
heading: "var(--font-syne)",
body: "var(--font-space-grotesk)",
mono: "var(--font-jetbrains-mono)"
}
};Change #00ffff to any hex color. The entire site updates: buttons, glows, borders, gradients, hover states. One value controls everything.
Step 9: Deploy
Vercel (recommended)
- Push your repo to GitHub
- Go to
vercel.com/new - Import your repository
- Add your environment variables
- Deploy
Vercel auto-detects Next.js. No build configuration needed.
Other platforms
The site works on Netlify, Railway, or any platform that supports Next.js. Run npm run build to generate the production build. Run npm start to serve it.
Project structure reference
portfolio/
├── app/ # Routes and pages
│ ├── (llms)/ # AI-readable content
│ ├── api/ # GitHub, Spotify, WakaTime
│ ├── blog/ # Blog listing + posts
│ ├── projects/ # Projects listing + pages
│ └── globals.css # All CSS variables
├── components/
│ ├── sections/ # Hero, About, Experience, etc.
│ ├── shared/ # Reusable animated components
│ ├── effects/ # Cursor, trail, skew
│ ├── easter-eggs/ # Konami, matrix, logo
│ └── ui/ # shadcn/ui primitives
├── config/
│ ├── site.config.ts # Your info (start here)
│ ├── seo.config.ts # Meta and structured data
│ ├── features.config.ts # Toggle effects on/off
│ ├── theme.config.ts # Colors and fonts
│ └── data/ # Experience, skills, testimonials
├── content/
│ ├── blog/ # MDX blog posts
│ └── projects/ # MDX project pages
├── lib/
│ ├── tech-icons.ts # Tech name to icon mapping
│ └── utils.ts # Helpers
└── public/
└── images/ # Your avatar and OG images
Common customizations
Add a new navigation link
Open config/navigation.config.ts and add an entry to mainNav:
{ label: "Resume", href: "/resume", icon: FileText }Add testimonials
Open config/data/testimonials.ts:
{
id: "1",
quote: "Shipped 3x faster after joining the team.",
name: "Jane Smith",
role: "Engineering Manager at Acme"
}Change fonts
The template loads 5 font families through next/font in lib/fonts.ts. Swap any of them by changing the import and CSS variable name.
Remove a section
Each homepage section is a separate component in components/sections/. Remove the import and the JSX tag from app/page.tsx. Done.
Updating the template
When the upstream template gets new features:
git remote add upstream https://github.com/karanjot786/portfolio.git
git fetch upstream
git merge upstream/mainYour content lives in content/ and config/. Template updates rarely conflict with those directories.
FAQ
Do I need to know React?
No. Adding content means creating MDX files with the right frontmatter. The template validates your fields at build time and tells you if something is wrong.
What if a tech icon is missing?
Add one line to lib/tech-icons.ts. Import the icon from react-icons/si and map it with a hex color.
How do I disable all animations?
Set every flag in features.config.ts to false. The site still works. It looks clean without the effects.
What is the license?
MIT. Use it for personal or commercial projects. No attribution required (but appreciated).
Get started
git clone https://github.com/karanjot786/portfolio.git
cd portfolio
npm install
npm run devEdit config/site.config.ts. Add your photo. Deploy to Vercel. Your portfolio is live.
If you find a bug or want a feature, open an issue on GitHub. Pull requests welcome.