Back to articles
8 min

Building a Personal Blog with Next.js 14: Choosing the Stack

Why I chose Next.js 14 for this website and what I learned from using the App Router.

Next.jsEngineeringFrontend

Building a Personal Blog with Next.js 14: Choosing the Stack

Why Next.js?

Before building the site, I compared several popular approaches:

| Option | Strengths | Trade-offs | |---|---|---| | Next.js | Strong SEO, good performance, broad ecosystem | A learning curve | | Gatsby | Fast static output and many plugins | Longer build times | | Astro | Lightweight and framework-agnostic | A younger ecosystem | | Hugo | Extremely fast builds | Go template syntax |

I ultimately chose Next.js 14 for the following reasons.

1. The App Router

// app/posts/[slug]/page.tsx
export async function generateStaticParams() {
  const posts = await getPosts()
  return posts.map((post) => ({
    slug: post.slug,
  }))
}

export default async function PostPage({ params }) {
  const post = await getPost(params.slug)
  return <Article post={post} />
}
  • Server Components reduce client-side JavaScript
  • Streaming supports progressive rendering
  • Layouts make shared page structure easier to maintain

2. Built-in performance tools

import Image from 'next/image'
import { Inter } from 'next/font/google'

const inter = Inter({ subsets: ['latin'] })

export default function Hero() {
  return (
    <div className={inter.className}>
      <Image
        src="/avatar.jpg"
        width={120}
        height={120}
        alt="Avatar"
        priority
      />
    </div>
  )
}
  • Image optimization provides modern formats and responsive sizing
  • Font optimization self-hosts fonts and reduces layout shifts
  • Bundle optimization removes unused code through tree shaking

3. Flexible data fetching

// Static generation with revalidation
export const revalidate = 3600

async function getData() {
  const response = await fetch('https://api.example.com/posts', {
    next: { revalidate: 3600 }
  })
  return response.json()
}

The framework supports several rendering modes:

  • SSG — generated during the build
  • ISR — regenerated incrementally
  • SSR — rendered for each request
  • CSR — rendered in the browser

Project structure

app/
├── layout.tsx          # Global layout
├── page.tsx            # Homepage
├── posts/
│   ├── page.tsx        # Article index
│   └── [slug]/
│       └── page.tsx    # Article page
├── resources/
│   └── page.tsx        # Resource library
└── api/
    └── submit/
        └── route.ts    # API route

components/
├── ui/                 # Reusable UI
├── layout/             # Shared layout
└── features/           # Feature components

lib/
├── posts.ts            # Article data
├── resources.ts        # Resource data
└── utils.ts            # Utilities

Performance results

The initial Lighthouse test produced:

  • Performance: 95
  • Accessibility: 98
  • Best Practices: 100
  • SEO: 100

Deployment

I chose Vercel for hosting:

npm i -g vercel
vercel --prod

The main benefits are zero-config Next.js support, a global CDN, preview deployments for every pull request, and integrated performance analytics.

Conclusion

Next.js 14 is a strong option for a modern personal website when you need:

  1. Reliable SEO
  2. Strong performance
  3. Flexible data fetching
  4. A mature ecosystem

The right stack is not the newest stack. It is the one that makes publishing and maintaining the site easier over time.