DEV Community

Will Holmes
Will Holmes

Posted on

Migrating to NextJs 13

Introduction

With all the buzz around NextJS 13 recently, I decided to take the opportunity to upgrade my personal website from 12 to 13.

The current setup is that I have a NextJS 12 app which serves a single page. It makes use of getServerSideProps to fetch data relating to my latest blog posts and my latest packages that I have published. It's pretty simple really and does the job for what I need right now.

The Migration Process

As part of this upgrade I wanted to give a shot at moving to the new app directory structure.

Firstly you have to run some updates to your package versions:

npm i next@latest react@latest react-dom@latest eslint-config-next@latest
# or
yarn upgrade next react react-dom eslint-config-next --latest
# or
pnpm up next react react-dom eslint-config-next --latest
Enter fullscreen mode Exit fullscreen mode

The above is taken from Vercel's upgrade page.

Secondly you need to adjust your next.config.js to include the following code block to enable app structure routing:

const nextConfig = {
  experimental: {
    appDir: true,
  },
};
Enter fullscreen mode Exit fullscreen mode

Once this has been done you then need to start migrating the different parts affected by the major bump. You can view them here at Vercel's hidden beta upgrade page which is frustratingly hard to find.

The most major parts to the upgrade that I found were:

  • Components are now react-server-components by default unless you specify use client at the top of your file. This can cause breakages in existing code. Previous hooks such as useRouter() have been replaced and the new ones are only available in client components.
  • The folder structure for routing. See a comparison below.

NextJS 12

project
│   
└───/pages
   │   index.tsx
   │   projects.tsx
   └───/api
       │   hello-world.ts

Enter fullscreen mode Exit fullscreen mode

vs

NextJS 13

project
│   
└───/app
    │   page.tsx (represents '/' route)
    └───/projects
        │   page.tsx (represents '/projects' route)
└───/pages
   └───/api (api routes are still in a pages folder)
       │   hello-world.ts

Enter fullscreen mode Exit fullscreen mode
  • Layouts have changed. You can share layouts between routes really easily or just have your normal layout at root. Layouts now just take a children prop typed as React.ReactNode. No typings of component and page props.
  • You do not need a <head> section inside of your layout. This is done via a head.tsx file which contains all the declarations of your head tags etc.
  • Caching requests with fetch inside of pages is so easy and code looks a lot cleaner than the old getServerSideProps().
fetch(url, { next: { revalidate 60 } }); // 60 second cache
Enter fullscreen mode Exit fullscreen mode
  • If you run into unhelpful errors then you will most likely struggle to find answers to your issues via Google. But that's due to the nature of new technology!
  • <Image /> tag has been upgraded - but you can revert to the old version by changing your import to something like this import Image from 'next/legacy/image';. I had to due to some errors that I ran into during my upgrade.
  • <Link /> tag now renders an <a> tag by default. So you no longer need to wrap an a tag inside of a Link tag.
  • No changes to api routes. They stay inside of the pages directory. Which I was surprised at, I hope this changes soon!

Deploying to Netlify

This was... painful to say the least.

Documentation isn't well presented and easily accessible. If you wish to use the new NextJS app structure, it is currently part of an extended version of their plugin to enable it for deployments.

Ensure you upgrade @netlify/plugin-nextjs to this:

"@netlify/plugin-nextjs": "^4.28.4-appdir.0",
Enter fullscreen mode Exit fullscreen mode

Your existing .toml setup should be fine as it is.

I also found that running the build locally and then serving it and testing the build was absolutely fine. But when deployed to netlify I got a 500. Turns out the issue was because there was an import of next/head which isn't used anymore and doesn't play nicely when running inside of netlify.

To help others with this in the future, below is a link of references that I found helpful when migrating my app:

  1. https://nextjs.org/docs/upgrading - Vercels snapshot update of upgrading.
  2. https://beta.nextjs.org/docs/upgrade-guide - Vercels in-depth (kinda) guide upgrading.
  3. https://www.netlify.com/blog/deploy-nextjs-13/ - Netlify's blog post around migrating to NextJS 13.

Overall

I spent a great deal of time migrating due to little gotcha's here and there. I'm happy it's done and I can test the new features it provides. But if my experience is anything to go by, I would allow a fair amount of time to do this with due care and attention. But maybe it was my late night coding brain that caused me to be so slow at upgrading.

Thanks for reading!👋

Top comments (0)