Logo
Published on

Journey to Modern: Upgrading My Blog Framework Stack

Authors
  • avatar
    Name
    Ismi Ammar
    Twitter

Journey to Modern: Upgrading My Blog Framework Stack

Recently, I embarked on a journey to upgrade my blog's underlying technology stack. What started as a routine dependency update turned into a comprehensive modernization effort that taught me valuable lessons about framework compatibility, dependency management, and the importance of incremental upgrades.

The Starting Point

My blog was running on:

  • Next.js 14.0.3 - A few versions behind
  • React 18.2.0 - Stable but not the latest
  • Tailwind CSS 3.3.3 - Missing some newer features
  • Original Contentlayer - Facing compatibility issues

While the blog was working fine, I noticed security warnings from GitHub's Dependabot showing 26 vulnerabilities across different severity levels. It was time for an upgrade.

The Challenge: Contentlayer Compatibility

The biggest challenge I faced was with Contentlayer, the content management layer that processes my MDX files. The original Contentlayer package had compatibility issues with newer versions of Next.js, particularly:

  • Template variable errors with Next.js 15
  • Import path issues
  • Windows-specific ESM problems

The Solution: Strategic Migration

1. Contentlayer Migration

I discovered Contentlayer2, a maintained fork that addresses the compatibility issues:

# Remove old contentlayer
yarn remove contentlayer next-contentlayer

# Install contentlayer2
yarn add contentlayer2 next-contentlayer2

2. Configuration Updates

Updated the imports and configuration:

// contentlayer.config.ts
import { defineDocumentType, ComputedFields, makeSource } from 'contentlayer2/source-files'

// next.config.js  
const { withContentlayer } = require('next-contentlayer2')

3. Import Path Fixes

The new contentlayer2 uses a different import pattern:

// Before
import { allBlogs } from 'contentlayer/generated'

// After  
import { allBlogs } from '.contentlayer/generated'

4. GitHub Slugger Update

The newer version requires an instance-based approach:

// Before
const formattedTag = GithubSlugger.slug(tag)

// After
const slugger = new GithubSlugger()
const formattedTag = slugger.slug(tag)

The Results

After the upgrade, my blog now runs on:

  • Next.js 14.2.20 - Latest stable version
  • React 18.3.1 - Latest stable version
  • TypeScript 5.8.3 - Latest version
  • Contentlayer2 0.5.8 - Actively maintained
  • All security vulnerabilities addressed

Key Lessons Learned

1. Incremental is Better Than Revolutionary

Instead of jumping to Next.js 15 and Tailwind 4, I chose stable versions that worked well together. This prevented breaking changes while still getting the benefits of updates.

2. Community Forks Can Save the Day

When official packages become unmaintained, community forks like Contentlayer2 can provide the continuity needed for modern development.

3. Test Early, Test Often

Having a working development environment throughout the upgrade process made it easier to identify and fix issues as they arose.

4. Documentation is Your Friend

Reading migration guides and changelogs helped me understand what changes were needed and why they were necessary.

The Upgrade Process

Here's the step-by-step process I followed:

  1. Create a dedicated branch for the upgrade work
  2. Update package.json using tools like npm-check-updates
  3. Install dependencies and identify compatibility issues
  4. Fix imports and configurations one by one
  5. Test thoroughly in development
  6. Commit incremental changes to track progress
  7. Create a pull request with detailed documentation

Performance Impact

The upgrade brought several performance improvements:

  • Faster build times with optimized dependencies
  • Better development experience with improved hot reload
  • Enhanced security with patched vulnerabilities
  • Future-proofing with actively maintained packages

Conclusion

Upgrading a blog's framework stack doesn't have to be a scary endeavor. With the right approach—incremental changes, thorough testing, and community support—it can actually be quite rewarding.

The key is to balance the desire for cutting-edge features with the need for stability. Sometimes, being one version behind the absolute latest is perfectly fine if it means everything works reliably together.

My blog is now running on a modern, secure, and maintainable foundation that should serve me well for the next few years. And the best part? The upgrade was completely transparent to readers—no downtime, no broken links, no lost content.

What's Next?

With the technical foundation now solid, I can focus on what really matters: creating great content. The upgraded stack gives me better developer tools, faster builds, and the confidence that my blog will continue to work reliably.

If you're considering a similar upgrade for your project, I hope this journey inspires you to take the plunge. The investment in time and effort is worth it for the peace of mind and improved development experience it provides.

Happy coding!