The Vercel Portfolio Starter Kit is an elegant solution for developers looking to create a modern, performant blog or portfolio website. This guide will break down its architecture, explain how it works under the hood, and show you how to make the most of its features.
For a lesser technical and shorterread, check out this blog post. Vercel Portfolio Starter Kit: Modern Blog with Next.js 14, MDX.
Project Functionality
At its core, the Vercel Portfolio Starter Kit is a Next.js 14 application designed to serve as a personal portfolio and blog platform. It combines several modern web development practices to deliver a fast, SEO-optimized, and developer-friendly experience.
Key Features
- MDX Support: Write content using Markdown with JSX components
- Static Site Generation: Pre-rendered pages for optimal performance
- SEO Optimization: Built-in meta tags, OpenGraph images, and sitemap
- RSS Feed: Automatic feed generation for content syndication
- Type Safety: Full TypeScript support
- Modern Styling: Tailwind CSS for responsive design
- Dynamic Routing: Automatic route generation for blog posts
Creating New Blog Posts
Creating a new blog post is straightforward. Simply add a new .mdx
file to the app/blog/posts
directory. Each post requires frontmatter metadata at the top of the file:
---
title: "Your Amazing Blog Post"
publishedAt: "2025-01-25"
summary: "A brief description of your post"
image: "optional-custom-og-image.jpg"
---
# Your content starts here
Regular markdown content with support for **bold**, *italic*, and more...
Frontmatter Fields
title
: The post title (required)publishedAt
: Publication date (required)summary
: Brief description for SEO and previews (required)image
: Custom OG image URL (optional)
Technical Concepts Explained
Before diving deeper, let's clarify some technical terms you'll encounter in this starter kit:
Open Graph (OG) Images and Meta Tags
Open Graph is a protocol developed by Facebook that turns web pages into rich objects in social media platforms. When you share a link on platforms like Facebook, Twitter, or LinkedIn, they look for Open Graph meta tags to display your content attractively.
The starter kit automatically generates OG images and meta tags for your blog posts:
<!-- Example of generated OG meta tags -->
<meta property="og:title" content="Your Blog Post Title" />
<meta property="og:description" content="Your post summary" />
<meta property="og:image" content="https://yourdomain.com/og-image.jpg" />
These tags ensure your content looks professional when shared on social media.
Static Site Generation (SSG) vs Server-Side Rendering (SSR)
The starter kit uses Static Site Generation, a crucial Next.js feature where pages are generated at build time rather than on each request. This means:
- Faster page loads: Pages are pre-rendered and cached
- Lower server costs: No need to render pages on every request
- Better SEO: Search engines can easily index static content
MDX: More than Just Markdown
MDX is a powerful extension of Markdown that allows you to:
- Use React components within your Markdown
- Create interactive blog posts
- Maintain consistency with reusable components
Example of MDX in action:
---
title: "My Post"
---
# Regular Markdown heading
<CustomComponent>
This is a React component inside Markdown!
</CustomComponent>
TypeScript Type Safety
The starter kit uses TypeScript for type safety. This means:
- Catch errors before they reach production
- Better developer experience with autocomplete
- Self-documenting code through type definitions
For example, the Metadata type ensures all blog posts have the required information:
type Metadata = {
title: string // Must be a string
publishedAt: string // Must be a string
summary: string // Must be a string
image?: string // Optional string
}
RSS Feeds and Content Syndication
RSS (Really Simple Syndication) is a web feed technology that allows users to get updates from your blog automatically. The starter kit generates an RSS feed, enabling:
- Readers to subscribe using RSS readers
- Content aggregators to fetch your latest posts
- Better content distribution across platforms
Under the Hood: How It Works
Let's break down the key components and processes that make this starter kit work.
1. MDX Processing and Routing
The blog uses a file-based routing system through Next.js App Router. Here's how the MDX processing pipeline works:
// app/blog/utils.ts
type Metadata = {
title: string
publishedAt: string
summary: string
image?: string
}
function parseFrontmatter(fileContent: string) {
let frontmatterRegex = /---\s*([\s\S]*?)\s*---/
let match = frontmatterRegex.exec(fileContent)
let frontMatterBlock = match![1]
let content = fileContent.replace(frontmatterRegex, '').trim()
let frontMatterLines = frontMatterBlock.trim().split('\n')
let metadata: Partial<Metadata> = {}
frontMatterLines.forEach((line) => {
let [key, ...valueArr] = line.split(': ')
let value = valueArr.join(': ').trim()
value = value.replace(/^['"](.*)['"]$/, '$1')
metadata[key.trim() as keyof Metadata] = value
})
return { metadata: metadata as Metadata, content }
}
2. Dynamic Route Generation
The starter kit automatically generates routes for each blog post using Next.js static site generation:
// app/blog/[slug]/page.tsx
export async function generateStaticParams() {
let posts = getBlogPosts()
return posts.map((post) => ({
slug: post.slug,
}))
}
3. Metadata and SEO
Each blog post automatically generates appropriate metadata for SEO:
export function generateMetadata({ params }) {
let post = getBlogPosts().find((post) => post.slug === params.slug)
if (!post) return
let {
title,
publishedAt: publishedTime,
summary: description,
image,
} = post.metadata
let ogImage = image
? image
: `${baseUrl}/og?title=${encodeURIComponent(title)}`
return {
title,
description,
openGraph: {
title,
description,
type: 'article',
publishedTime,
url: `${baseUrl}/blog/${post.slug}`,
images: [{ url: ogImage }],
},
twitter: {
card: 'summary_large_image',
title,
description,
images: [ogImage],
},
}
}
Component Architecture
The starter kit uses a modular component architecture for maintainability and reusability:
Key Components
-
Layout Component (
app/layout.tsx
)- Provides the base layout structure
- Handles global styles and fonts
- Includes navigation and footer
-
MDX Component (
app/components/mdx.tsx
)- Renders MDX content with custom components
- Handles code syntax highlighting
- Provides custom React components for MDX
-
Blog Page Component (
app/blog/[slug]/page.tsx
)- Handles dynamic routing for blog posts
- Generates metadata
- Renders individual blog posts
-
Utils (
app/blog/utils.ts
)- Provides helper functions for MDX processing
- Handles date formatting
- Manages blog post data fetching
Edge Network and CDN
When you deploy to Vercel, your site is automatically distributed across a global Edge Network. This means:
- Content is served from servers closest to your users
- Faster page loads worldwide
- Automatic scaling during traffic spikes
- Built-in DDoS protection
Deployment to Vercel
Deploying your portfolio is seamless with Vercel:
- Push your code to a Git repository (GitHub, GitLab, or Bitbucket)
- Import the repository in your Vercel dashboard
- Configure your project settings (if needed)
- Deploy!
Vercel will automatically:
- Build your Next.js application
- Generate static pages for your blog posts
- Deploy to their global edge network
- Provide a custom domain or
.vercel.app
subdomain - Set up continuous deployment
Customization Tips
- Styling: Modify
app/global.css
for custom styles using Tailwind CSS - Components: Add custom components in
app/components
- Layout: Customize
app/layout.tsx
for site-wide changes - Metadata: Update site metadata in
app/layout.tsx
- Blog Features: Extend
app/blog/utils.ts
for additional functionality
Performance Optimization
The starter kit leverages Next.js 14's built-in performance features to deliver an optimized user experience:
Image Optimization
Next.js provides automatic image optimization through its next/image
component:
import Image from 'next/image'
// The image is automatically optimized
<Image
src="/blog-image.jpg"
alt="Blog image"
width={800}
height={400}
priority={true} // For above-the-fold images
/>
This optimization includes:
- Automatic WebP/AVIF conversion based on browser support
- Responsive image generation for different device sizes
- Lazy loading by default (unless
priority
is set) - Preventing Cumulative Layout Shift (CLS) with required dimensions
- Image caching at the edge
Font Loading Strategy
The starter kit implements font optimization using the Next.js Font system:
import { Inter } from 'next/font/google'
const inter = Inter({
subsets: ['latin'],
display: 'swap',
})
This provides:
- Self-hosted fonts with zero layout shift
- Automatic font subsetting (only loading characters you use)
- Built-in CSS
size-adjust
for fallback fonts - Preloading of font files for optimal loading
Bundle Optimization
Since this is a static site, Next.js optimizes the bundle in several ways:
- Static Page Generation:
// All pages are pre-rendered at build time
export async function generateStaticParams() {
let posts = getBlogPosts()
return posts.map((post) => ({
slug: post.slug,
}))
}
- Component-Level Code Splitting:
// Components are automatically code-split
import dynamic from 'next/dynamic'
const DynamicComponent = dynamic(() => import('./components/heavy-component'), {
loading: () => <p>Loading...</p>
})
The build process:
- Creates separate chunks for each page
- Automatically splits shared components
- Generates static HTML for each route
- Optimizes and minifies JavaScript
- Tree-shakes unused code
Navigation and Data Loading
Rather than traditional prefetching, the starter kit benefits from Next.js 14's App Router and static generation:
- Static HTML: All pages are pre-rendered as static HTML at build time
- Route Cache: Static routes are cached at the edge
- Instant Navigation: Page transitions are immediate since content is already available
- Zero Client-Side Runtime: Minimal JavaScript needed for static pages
This approach means:
- Initial page load is pure HTML (no JavaScript required)
- Subsequent navigations are instant
- Search engines see the full content immediately
- Perfect Lighthouse scores for performance
The combination of these optimizations results in:
- Sub-second Time to First Byte (TTFB)
- Perfect Core Web Vitals scores
- Optimal SEO performance
- Minimal server costs due to static generation
Static Site Generation (SSG)
Finally, let's take a look at Static Site Generation (SSG) and how it is used in the Vercel Portfolio Starter Kit. The starter kit uses Static Site Generation, a crucial Next.js feature where pages are generated at build time rather than on each request. This means:
- Faster page loads: Pages are pre-rendered and cached
- Content is available immediately
- Search engines see the full content immediately
- Perfect Lighthouse scores for performance
In Next.js, the generateStaticParams
function is used in dynamic routes when you want to statically generate pages at build time. It's part of the app
directory (introduced in Next.js 13) and is used alongside the pages
or [param]
pattern for dynamic routes.
When you're using static site generation (SSG) for a dynamic route, you need to specify what the possible dynamic parameters are, so Next.js can generate a static HTML page for each of them at build time. The generateStaticParams
function is responsible for returning an array of parameters that Next.js will use to generate these static pages.
Key Points:
generateStaticParams
runs at build time.- It allows you to specify the dynamic route parameters that should have static pages generated.
- It works with routes that use dynamic segments (e.g.,
[id].js
or[slug].js
).
Example Usage
Assume you have a route like /posts/[id]
and you want to statically generate pages for specific post IDs.
Here’s how you might use generateStaticParams
in the app directory:
-
Define your dynamic route:
Let's say you have a file called
page.js
inside theapp/posts/[id]
directory:// app/posts/[id]/page.js export default function PostPage({ params }) { return <div>Post ID: {params.id}</div>; }
-
Define
generateStaticParams
:In the same directory, you create a
generateStaticParams
function that returns an array of all the dynamic parameters you want to pre-generate.// app/posts/[id]/generateStaticParams.js export async function generateStaticParams() { // You can fetch data from an API, a database, or a file const posts = await fetch('https://api.example.com/posts') .then(res => res.json()); // Generate an array of params that Next.js will use to create static pages return posts.map(post => ({ id: post.id.toString(), // The parameter in the dynamic route })); }
-
This will return an array of objects with the
id
parameter for each post you want to generate a page for. -
If your API returns an array of posts, the
generateStaticParams
function will loop over them and return an array with theid
for each post. For example:[ { id: '1' }, { id: '2' }, { id: '3' }, ]
-
-
Result:
Next.js will now generate static pages for each post at build time, like
/posts/1
,/posts/2
, and/posts/3
.
Why Use generateStaticParams
?
You might want to use generateStaticParams
when:
- You want to pre-render dynamic pages for a set of known parameters (e.g., blog posts, product pages, etc.).
- You’re working with a headless CMS, API, or database and you know what data you need at build time.
- You have dynamic routes that need to be generated ahead of time for better performance and SEO.
When to Use:
generateStaticParams
is specific to dynamic routes in theapp
directory. If you’re using pages in the older/pages
directory, you would usegetStaticPaths
instead.
Let me know if you need more clarification or further examples!
Conclusion
The Vercel Portfolio Starter Kit provides a solid foundation for building a modern blog or portfolio. Its combination of Next.js, MDX, and Vercel's infrastructure creates a developer-friendly environment while ensuring excellent performance and SEO.
Whether you're creating a personal blog, technical documentation, or a portfolio site, this starter kit gives you the tools to focus on content while maintaining professional quality standards.