A highly configurable, open-source portfolio template built with Next.js. Auto-syncs with GitHub, features a powerful MDX blog, and offers modular sections you can mix, match, and customize.
Built for developers, writers, and creators who want full control.
Quick Start · Report Bug · Request Feature
- Fully Modular - Enable/disable sections, reorder them, or add your own
- GitHub Auto-Sync - Repositories and blog articles sync automatically
- MDX Blog - Write with markdown, embed charts, math equations, and components
- Professional UI - Beautiful design with dark mode and responsive layouts
- Lightning Fast - ISR (Incremental Static Regeneration) for optimal performance
- Config-Driven - Customize everything through simple config files
- Deploy Anywhere - Vercel, Docker, Raspberry Pi, or any Node.js host
Less is more. This template embraces minimalism and simplicity. Choose 3-5 sections that best represent you—not all of them. A focused portfolio is more impactful than a cluttered one.
The modular architecture gives you complete control: enable what matters, disable what doesn't, and add custom sections as needed.
Click the green "Use this template" button at the top of this repo and select "Create a new repository". This gives you a clean copy with no fork link—and you can make it private from the start.
Only fork or clone directly if you want to contribute back to this template. For personal use, always use the template button.
git clone https://github.com/YOUR_USERNAME/your-repo-name.git
cd your-repo-name
npm installcp .env.local.example .env.localEdit .env.local with your GitHub username and personal access token (needs repo scope):
NEXT_PUBLIC_GITHUB_USERNAME=your-username
GITHUB_TOKEN=ghp_your_token
ARTICLES_REPO_URL=https://github.com/your-username/articles
NEXT_PUBLIC_SITE_URL=http://localhost:3000
NEXT_PUBLIC_SITE_NAME=Your NameOption A: Automated
./scripts/setup-articles-repo.sh # Requires GitHub CLIOption B: Manual - Create a public repo with this structure:
articles/
└── my-first-article/
├── metadata.json
└── index.mdx
npm run devVisit http://localhost:3000 and start customizing!
The key differentiator. Configure your home page sections in src/config/home.ts:
export const homeConfig = {
repos: { enabled: true },
articles: { enabled: true, count: 3 },
experience: { enabled: true },
education: { enabled: false }, // Disable sections you don't need
certifications: { enabled: false },
talks: { enabled: false },
now: { enabled: true },
testimonials: { enabled: false },
connect: { enabled: true },
};
// Reorder sections by changing array order
export const sectionOrder = [
"repos",
"articles",
"experience",
"now",
"connect",
];Available sections:
- All components in
src/components/home/ - Each has its own config file (e.g.,
src/config/experience.ts,src/config/testimonials.ts) - Add custom sections by creating new components and config files
Best practice: Choose 3-5 sections max. Keep it minimal and impactful.
Edit these config files:
src/config/site.ts- Social links, site metadatasrc/config/experience.ts- Work historysrc/config/education.ts- Education backgroundsrc/config/testimonials.ts- Recommendationssrc/config/certifications.ts- Professional credentialssrc/config/talks.ts- Speaking engagementssrc/config/now.ts- Current projectssrc/components/home/HeroSection.tsx- Bio and intro
This template uses shadcn/ui theming.
Recommended: Use TweakCN Theme Editor to generate custom themes visually, then copy the generated CSS variables into src/app/globals.css.
To customize manually:
- Go to ui.shadcn.com/themes
- Pick a theme (e.g. Blue, Green, Orange) and select Copy code with the
oklchformat - Replace the
:rootand dark mode CSS variables insrc/app/globals.css
For example, applying the Blue theme:
:root {
--radius: 0.65rem;
--background: oklch(1 0 0);
--foreground: oklch(0.141 0.005 285.823);
--primary: oklch(0.488 0.243 264.376);
--primary-foreground: oklch(0.97 0.014 254.604);
/* ... paste the rest of the variables from shadcn */
}
@media (prefers-color-scheme: dark) {
:root {
--background: oklch(0.141 0.005 285.823);
--foreground: oklch(0.985 0 0);
--primary: oklch(0.488 0.243 264.376);
/* ... dark mode variables */
}
}Note: Only replace the
:root { ... }and@media (prefers-color-scheme: dark) { :root { ... } }blocks. Leave the@theme inline,@layer base, and other sections untouched.
The default font is Geist. You can swap it with any Google Font or your own local font files.
Option A: Google Fonts (free)
Edit src/app/layout.tsx:
import { Inter } from "next/font/google";
const inter = Inter({
variable: "--font-sans-var", // Reuse the same CSS variable
subsets: ["latin"],
});
// In the <body> tag:
<body className={`${inter.variable} antialiased`}>You can use any font from fonts.google.com. Just replace Inter with your chosen font's import name (e.g. Roboto, Outfit, Space_Grotesk).
Option B: Local font files (purchased/custom)
Place your font files in src/app/fonts/ and use next/font/local:
import localFont from "next/font/local";
const myFont = localFont({
src: [
{ path: "./fonts/MyFont-Regular.woff2", weight: "400", style: "normal" },
{ path: "./fonts/MyFont-Medium.woff2", weight: "500", style: "normal" },
{ path: "./fonts/MyFont-Bold.woff2", weight: "700", style: "normal" },
],
variable: "--font-sans-var",
});
// In the <body> tag:
<body className={`${myFont.variable} antialiased`}>Tip: The
--font-sans-varCSS variable is what the entire site reads from, so swapping the font source inlayout.tsxis the only change needed.
articles/
└── my-article/
├── metadata.json # Title, date, tags, authors
├── index.mdx # Article content
└── assets/ # Optional: images, files
metadata.json:
{
"title": "Article Title",
"summary": "Brief description",
"date": "2026-02-07",
"tags": ["javascript"],
"published": true,
"authors": [{ "name": "Your Name", "linkedIn": "..." }]
}- Markdown: Tables, code blocks, task lists
- Math: Inline
$E=mc^2$and block equations$$...$$ - Charts:
<CustomBarChart>,<CustomLineChart>,<CustomAreaChart>,<CustomPieChart> - Callouts:
<Callout type="info|warning|error|success"> - Images:
for local files
See /mdx-reference/ for a complete example with all features.
- Push to GitHub
- Import in Vercel
- Add environment variables
- Deploy
docker build -f docker/Dockerfile.pi -t portfolio .
docker run -p 3000:3000 --env-file .env portfolioOr with Docker Compose:
cd docker && docker-compose up -dIncremental Static Regeneration (ISR) automatically updates content from GitHub:
- Articles sync every 5 minutes
- Repos sync every 10 minutes
- Graceful fallbacks if GitHub API is unavailable
MDX articles are fetched from your GitHub repo and compiled server-side with support for GFM, math equations (KaTeX), syntax highlighting, and interactive charts.
- Create a component in
src/components/home/YourSection.tsx - Create a config file in
src/config/yourSection.ts - Add to
src/config/home.ts:export const homeConfig = { // ... other sections yourSection: { enabled: true }, } export const sectionOrder = [..., 'yourSection']
- Import and render in
src/app/page.tsx
Add UI components: npx shadcn@latest add [component] from ui.shadcn.com
Next.js 15 · TypeScript · Tailwind CSS · shadcn/ui · MDX · Recharts · KaTeX · GitHub API
This template is designed to be used via the "Use this template" button. You don't need to contribute back—make it your own!
Only fork/clone this repo directly if you'd like to improve the template for everyone:
- New modular sections (education, skills, projects, etc.)
- Config improvements that make customization easier
- Bug fixes and performance improvements
- Documentation enhancements
- Accessibility improvements
- Fork this repo
- Create a branch:
git checkout -b feature/your-feature - Make your changes (follow existing code style)
- Test:
npm run dev && npm run build - Commit:
git commit -m "feat: description" - Push and open a PR
Focus areas:
- New home page sections that others would find useful
- Easier configuration patterns
- Better defaults and examples
- Improved modularity
Open an issue to discuss ideas or report bugs.
MIT License - use freely for personal or commercial projects.
The contact page includes a small "Made with ABOUTME.md" attribution. You're free to remove it — no hard feelings. If you enjoy the template, a star on GitHub goes a long way in helping others discover it.
Questions? Open an issue · Need inspiration? Check /mdx-reference/ for examples
Built with Next.js, Tailwind CSS, shadcn/ui, MDX, and Recharts.