Drew‘s Tech Blog

Migrating to Next.js for improved SEO

By Drew Thomas | Published 4/1/2024

Introduction

When I first built my blog, I didn't expect to finish the first iteration so quickly [Read about my experience here]. I originally used Create React App (CRA) as it's what I'm familiar with and used in college when I did more web development. I recognized that if I wanted to grow the blog, a single page application (SPA) would lose some key benefits, so I went in search of alternatives. In this post I'll cover why I chose Next.js, the alternatives I looked at, and my experience migrating.

Why I Chose to Migrate to Next.js

There were several compelling reasons that led me to migrate my project to Next.js:

  1. Static Site Generation (SSG): Next.js supports SSG out of the box. You can generate static HTML files at build time, which can be served directly from a CDN, resulting in fast page loads and reduced server costs. This is particularly useful for blogs, documentation sites, and other content-heavy applications. Specifically for me, I wanted my CloudFront distribution to send an HTML page with a custom title, description, and optionally og meta tags in the HTML head. This meant finally when I share my site on LinkedIn, it will show the title and excerpt on the little image that renders when I paste my blog link. This also leads to improved SEO.
  2. File-based Routing: Next.js follows a simple and intuitive file-based routing system. You can create pages by adding directories to the app directory, and Next.js automatically handles the routing for you. This approach makes it easy to organize and navigate through your application's pages. I was able to maintain the same file structure I created with React Router with ease, and this reminded me of my PHP days on Ubuntu servers which was a nostalgic moment.
  3. Built-in Optimizations: One of the coolest things I noticed with Next.js was its optimizations. I did not create any benchmarks as my Sunday was interesting enough that I felt I could make one dataless driven decision; however, anecdotally, the multi-page application felt just as fast as the single-page application. Behind the scenes, Next.js fetches the files that are linked to on the current page, so when the user clicks the link, the content is already loaded in their browser. There' plenty more things it does for CSS, image loading, fonts etc.
  4. Native Features: One of the things I appreciated most about Next.js was its built-in features that allowed me to remove custom code I had previously written. For example, Next.js provides a Link component that automatically handles scroll restoration, ensuring that the page scrolls back to the top when navigating between pages, something I previously (poorly) handled with a useEffect hook. Next.js also offers built-in support for Google Analytics through its @next/third-parties/google package. This felt cleaner than react-ga4.
  5. Server-Side Rendering (SSR): Next.js offers built-in support for SSR, which can significantly improve the initial load time and SEO of your application. With SSR, the server sends a fully rendered HTML page to the client, providing a better user experience and faster content visibility. Next.js allows you to create API endpoints within your application using Node.js. This feature eliminates the need for a separate backend server, simplifying your development workflow and enabling you to build full-stack applications with ease. While I have no need for these features at the moment, I enjoy knowing they're there when I want to add features such as comments and likes to my blog.

Alternatives Considered

Before deciding to migrate to Next.js, I explored a few other popular frameworks and tools for building static and server-rendered React applications. Here are the alternatives I considered:

  1. Astro: Astro is a modern static site builder that allows you to use various frontend frameworks, including React, to create fast and lightweight websites. It offers a simple and intuitive development experience, with a focus on performance and flexibility. However, I found that Astro's ecosystem and community were not as mature as Next.js, and it lacked some of the advanced features and optimizations that Next.js provides out of the box.
  2. React Static: React Static is a powerful static site generator for React applications. It offers a simple and flexible development workflow, with support for code splitting, prefetching, and optimized builds. I about went with this option, as it seemed to offer most of what I wanted for SEO, while remaining lightweight, but I found the project stopped being funded during Covid.
  3. Gatsby.js: Gatsby.js is a popular static site generator built with React and GraphQL. It offers a rich plugin ecosystem, powerful data layer, and excellent performance optimizations. Gatsby.js is well-suited for building content-heavy websites and applications, such as blogs and e-commerce sites. However, I found that Gatsby.js had a steeper learning curve compared to Next.js. For my use case of strictly static-site generation, there was nothing compelling to win me over.

After evaluating these alternatives, I ultimately chose Next.js for its comprehensive feature set, excellent developer experience, and strong community support. Next.js struck the right balance between simplicity and flexibility, allowing me to easily migrate my existing React application while leveraging the benefits of static site generation and build-in optimizations.

The Migration Process

As a starting point, I referred to the excellent Next.js documentation throughout the migration process. The documentation is well-structured, comprehensive, and full of practical examples, making it a valuable resource for developers of all skill levels. Their guide on upgrading from Create React App to Next.js was one of the best I've followed along with.

To perform the migration from CRA to Next.js, I first updated a page of my app by hand so I could learn the framework and its options. I decided to migrate fromstyled-components, a CSS-In-JS library, to scss modules, so I could take advantage of build-time rendering/CSS optimizations that Next.js provides. I also migrated from React Router to Next's Link components. After this, I sought the assistance of Opus. After feeding it the example before and after files I just created, Opus was able to take my other files as input and then output the correct scss and tsx files. After copying and pasting these into my IDE I only had to make a few minor adjustments and I was good to go. The full migration took me less than a day.

During the migration, I encountered a few minor issues. For example, I needed to set the trailingSlash option in the next.config.js file to ensure that static pages were rendered correctly with trailing slashes in the URLs, something that caused refreshes of pages to render the home page instead. Since I migrated from React Router and styled-components, I also needed to add active classes to my header links to maintain the same styling.

Conclusion

Migrating from Create React App to Next.js has been a rewarding experience. I got to learn the new industry leading framework, significantly enhanced my application's performance, and I finally got my LinkedIn posts to include the title of my blog posts!

If you're considering migrating your React application to Next.js, I highly recommend exploring the framework and leveraging the excellent documentation and community resources available. For myself, I'll be using Next.js as the base for most of my future projects. Happy coding!