In this article, you will learn how transform a React app into a Next.js app.
So, while refactoring my portfolio, I decided to upgrade it from React to Next.js. In this article I will tell you how I did it, as I find it might be able to help you out. I found no specific orientation on Next.js official docs about how to do it, and just a few posts about it. So I figured probably the easiest and safest way, for me, would be to create a Next app and basically transfer my content to it - or transfer its configuration to my project.
But, before that, you could be asking yourself:
Why use Next.js?
Well, in my case, besides the facilities Next.js brings, I had a few other reasons to use it in my portfolio. Although it is a relatively simple website, I have been working with Next.js for a few months now and had no demo with it in my GitHub to show. Also I wanted to use Contentlayer as it is a way I can have my curriculum and all site contents written in markdown and easily manage the content and have my types generated for Typescript use. I couldn’t use Contentlayer with React since it is, at this moment, for Next.js applications only. Hence, I thought it would be interesting to upgrade my project to Next.js.
And what does Next.js do?
Next.js is a flexible React framework that improves both developer and user experiences. About developer experience, by the way, Next.js has amazing documentation and tutorials, I highly recommend it! It makes it easy to do routing, loading and error states. It also has server-side and client-side rendering you can choose for each component, reducing the JS code to run on the client. I will tell more about Next.js features in another post.
Enought talking, let’s get going!
The React project
I had a project in React (v18) deployed on (Vercel). This is how the project folder structure looked like:
Migrating project to Next.js
So, first of all, I am versioning my code with git. If you are a beginner, I recommend you start getting familiar with code versioning as soon as possible. After the project has been initialised with git, I opened the terminal and created a new branch on my code to work on this modifications. This way I leave it separate from the main branch and have full control on what I’m doing.
git checkout -b nextjs
Then, on branch nextjs
, I created a next app on the root of my project.
npx create-next-app@latest
Here you need to name your project. You can give any name you want, because we will transfer the files to the current project. For this example, I called it my-app
. As I intend to use Typescript, Tailwind and ESLint, I added all of them on the installation, just by answering to the prompts on the terminal. Also used App router, did not add src
folder and used the import alias @/
. You can do as you wish.
Here are the instructions from the official docs, if you need more info on the installation: https://nextjs.org/docs/getting-started/installation.
Then, a new folder was created inside my project folder with all the initial files from the Next app. The whole folder structure now looks like this:
Note that inside the root folder I have the React files (package.json
, package-lock.json
, .gitignore
…) and the new Next.js project folder with its files.
Adjusting the files structure
Now, you need to define the configuration files of your project. Let’s start with package.json
. I suggest you compare your original package.json
with your Next app's package.json
and copy to the original one what is missing. Replace the "scripts"
with the scripts from the Next app, keep the dependencies and devDependencies you use and add the ones from the Next app to your files.
Important: My first attempt was erasing and replacing
package.json
,package-lock.json
and.gitignore
, but I had some problems with git versioning due to it. So I suggest replacing the content of these files instead of deleting the file and pasting the new one. I consider it a better idea also because you use the opportunity to read the files and keep the dependencies you are using, so you don’t have to install them again.
Do the same with .gitignore
. See what’s different between yours and the Next app and copy the Next app content to your file.
If you are going to use Tailwind and already have a tailwind.config.js
, like me, you can keep your file and just convert it to Typescript if you wish.
Once you have kept what you need on your config files: package.json
, tailwind.config.json
, tsconfig.json
(if you are already using Typescript), .gitignore
, you can move the other files from the Next app to the React app (your original app): next-env.d.ts
, .eslintrc.json
, next.config.js
, postcss.config.js
and tsconfig.json
(if you don’t already have one) and the app/
folder. The image below illustrates these changes.
Now, you can delete what you won’t need from your react-app. Don’t forget your README.md
. If you already have one and want to keep it, you can’t delete it from the original files!
I deleted src/index.js
, src/reportWebVitals.js
and my test-related files (since I decided not to apply tests now).
Now, my folder structure looks like this:
Adjusting the content
Now the config files are in place it’s time to adjust your content to how Next.js expects to find it. To keep it simple until I'm sure it is working, I started transferring everything from src/App.js
to app/page.tsx
- all the logic, states and jsx.
In this process, you may need to:
- Check if the imports are still working or need any adjust.
- If you are moving from JS to TS, you will need to define some types.
- Check if you need to use client components in your page or any component. Since I am using
useState
anduseEffect
hooks on my page, I had to. To do it, just add'use client'
on the top of the file. Example:
// app/page.tsx
'use client'
import { useState, useEffect } from 'react'
// ... rest of your code
Later, I moved my CSS variables from src/App.css
and src/index.css
to app/globals.css
and checked if app/layout.tsx
and app/page.tsx
are importing the app/globals.css
.
Then, I imported my font on app/layout.tsx
using Next-font and extended it as a Tailwind class, as described in the Next.js official docs - you can find it here.
Then, after the new package.json
and all files are in place, run in your terminal:
npm install
npm run dev
npm install
will update your package-lock.json
according to your package.json
and install all the dependencies, hence updating node_modules
accordingly as well. If it works as expected, npm run dev
will start the localhost server for you and you can see your project running!
At this point, I came across some compatibility issues I had to deal with (you might have different ones, depending on how your project is). Mine were:
- Some local files I was importing with the
require()
method and it was not working (insrc
andsrcSet
attributes in images andhref
attributes in anchor tag). I found moving the local files to/public/assets/
and referring their location directly (without mentioning the/public
) solved the issue. Let me show:
- One
<img />
tag was not working, so I used next/image.
Once, you’re sure everything is working and that you’ve transferred all the Next app info you need to your original project, you can delete the my-app
folder you created and the files you will not need anymore (in my case, src/App.js
, src/App.css
and src/index.css
).
Shipping to production
With all the adjusts done, my project was running smoothly on development. But, when I commited and pushed the modifications to the remote branch, Vercel tried to deploy my branch and I had errors on deploy.
What happened is that the project on Vercel has some config related to the framework. It identifies the framework and defines the settings to the deploy (you can read more about it here. And, at this point, my main
branch was on React and my nextjs
branch was on Next.js. I couldn’t figure out a way to have distinct settings for each branch, so my problem was only solved when I integrated the branch into main
, went to the Project Settings on Vercel, switched the Framework Preset to Next.js and tried to redeploy. This is how the Project Settings page looks now:
Now, my project is running in both development and production! This is how I got my project running with Next.js without rebuilding it from scratch, I hope it helps you in anyway.
Thanks for reading!
Top comments (0)