Deeper Dive: Understanding the Vercel Portfolio Starter Kit

Jan 25, 2025

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

  1. Layout Component (app/layout.tsx)

    • Provides the base layout structure
    • Handles global styles and fonts
    • Includes navigation and footer
  2. MDX Component (app/components/mdx.tsx)

    • Renders MDX content with custom components
    • Handles code syntax highlighting
    • Provides custom React components for MDX
  3. Blog Page Component (app/blog/[slug]/page.tsx)

    • Handles dynamic routing for blog posts
    • Generates metadata
    • Renders individual blog posts
  4. 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:

  1. Push your code to a Git repository (GitHub, GitLab, or Bitbucket)
  2. Import the repository in your Vercel dashboard
  3. Configure your project settings (if needed)
  4. 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

  1. Styling: Modify app/global.css for custom styles using Tailwind CSS
  2. Components: Add custom components in app/components
  3. Layout: Customize app/layout.tsx for site-wide changes
  4. Metadata: Update site metadata in app/layout.tsx
  5. 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:

  1. 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,
  }))
}
  1. 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

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:

  1. Define your dynamic route:

    Let's say you have a file called page.js inside the app/posts/[id] directory:

    // app/posts/[id]/page.js
    export default function PostPage({ params }) {
      return <div>Post ID: {params.id}</div>;
    }
  2. 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 the id for each post. For example:

      [
        { id: '1' },
        { id: '2' },
        { id: '3' },
      ]
  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 the app directory. If you’re using pages in the older /pages directory, you would use getStaticPaths 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.