Next.js Version Upgrade (v14 ➡️ v15)

Reasons for the Version Upgrade
The latest version of Next.js is v15. And this version was announced in October 2024 (Stable).
The starting point of writing this portfolio/blog module (the blog web you are currently viewing) was February 2025. At that time, another module I referenced heavily while creating this module was written based on Next.js v14. So, naturally, this module was also created based on v14.
Most of the desired features have been added to the module, and I was thinking about what to do next when I decided to try upgrading the Next.js version.
Upgrade Process
Chat with LLM
I was unsure how to proceed with the upgrade, especially since I had never upgraded the version of an FE module before. So I decided to get help from Cursor, which I recently started using.
I opened the package.json file in Cursor and asked a question through the Chat
function.
I want to upgrade the Next.js version from the current 14.2.5 to version 15. Please tell me what I should consider.
The LLM responded as follows:
Here are the important considerations for upgrading from Next.js 14 to 15:
1. Major Changes:
- Next.js 15 now uses App Router as the default router.
- Requires Node.js 18.17 or higher.
- Requires React 18.2.0 or higher.
2. package.json Updates Required
{
"dependencies": {
"next": "^15.0.0",
"@next/third-parties": "^15.0.0"
// ... existing code ...
}
}
3. Compatibility Checks Required:
- You need to upgrade Next.js related packages such as @next/third-parties that you are currently using.
- You need to check the compatibility of other packages used in the project with Next.js 15.
- Especially for next-auth, please check compatibility with Next.js 15.
4. Recommended Upgrade Procedure:
- First, test in a development environment.
- Update the version in package.json and run npm install or yarn install.
- Build and test the entire application.
- Focus testing on the following features:
- Routing
- API routes
- Middleware
- Image optimization
- MDX related features
5. Backup Recommended
- Please back up the current code before upgrading.
- If you are using git, please proceed with the upgrade in a new branch.
6. Performance Monitoring
- Please monitor performance changes after the upgrade.
- If you are using Vercel Analytics, it is recommended to check the performance metrics.
It is recommended to proceed with the upgrade step by step, considering these points.
I was vaguely thinking about how to upgrade the version, but seeing the concrete execution plan, I thought I could proceed as is. However, there are a few inaccuracies here. For example, the statement that App Router has become the default router since Next.js 15 is slightly different from the truth. And the required updates to package.json are also a bit strange. This is because the @next/third-parties
module is already using the latest version.
Although there were a few inaccuracies, overall, I thought it was a very good upgrade execution plan.
So, I decided to start by changing the version of the next
module to the latest and updating the versions of modules related to this module to the latest. After that, I would build the module and check for any issues.
Module Version Changes
The list below shows the names of the modules changed in the package.json of my portfolio/blog module for this Next.js version upgrade and the changed version for each module.
- "next":
14.2.5
→15.2.1
- The current latest Next.js version is 15.2.1. (As of March 7, 2025)
- "react":
^18
→^19.0.0
- It wasn't necessary to do this because Next.js v15 also supports react 18, but I decided to upgrade the react version as well.
- "react-dom":
^18
→^19.0.0
- Along with the react version, I also upgraded the react-dom version to 19.
- "@types/react":
^18
→^19
- Along with the react version, I also upgraded the react-dom version to 19.
- "@types/react-dom":
^18
→^19
- Along with the react version, I also upgraded the react-dom version to 19.
- "eslint":
^8
→^9
- The Next.js official documentation says that it supports ESLint 9. So I upgraded the version as well.
- "eslint-config-next":
14.2.5
→15.2.1
- Changed from 14.2.5 to 15.2.1 along with the next module.
- For other modules, I judged that there were no major compatibility issues with the Next.js version.
After changing the module versions, I deleted the .next
, .velite
, and node_modules
directories and installed all the modules through npm install
.
Then I ran the Next.js server locally through the npm run dev
command.
Module Code Modification
With a slightly trembling heart, I accessed the browser and entered localhost:3000. Fortunately, the Home menu was executed without any problems on the screen. I could see a very small Next.js icon in the lower left corner, which I had not seen before.

There were no problems on the browser screen. But when I looked at the server logs, the following error log was printed.
Error: Route "/blog/[...slug]" used `params.slug`. `params` should be awaited before using its properties.
Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis
at getBlogFromParams (src/app/blog/[...slug]/page.tsx:22:15)
at BlogPage (src/app/blog/[...slug]/page.tsx:62:21)
20 | searchParams: BlogPageProps["searchParams"]
21 | ) {
> 22 | const slug = params?.slug?.join("/");
The above is a server error log that is printed when accessing the /blog/{slug}
path.
The path of the server component that handles this routing path is app/blog/[...slug]/page.tsx
.
The original code for this component is as follows.
type BlogPageProps = {
params: {
slug: string[];
};
searchParams: {
lang?: string;
};
};
async function getBlogFromParams(
params: BlogPageProps["params"],
searchParams: BlogPageProps["searchParams"]
) {
const slug = params?.slug?.join("/");
// find blog by params and return it
}
const BlogPage = async ({ params, searchParams }: BlogPageProps) => {
const blog = await getBlogFromParams(params, searchParams);
return <BlogPageDetail blog={blog} />;
};
- [1-8]: Defines the component's argument type through
type BlogPageProps
. - [10-17]: Receives the blog post ID and returns the blog post data.
- [19-22]: Component code. Calls the getBlogFromParams function to obtain the blog and then renders the detailed blog post page through the BlogPageDetail component.
The error here occurs on line 14.
Cursor can select a log in the CLI and send that message to Chat
. In the CLI window, select the message you want to analyze the cause of the error, and press Command + L
to reflect it directly in the chat interface. And if you press enter immediately, the LLM will analyze the cause of the error and suggest a solution.
The cause and solution suggested by the LLM are as follows.
I will explain the new error that occurred in Next.js 15. This error occurs when you try to use searchParams synchronously. In Next.js 15, searchParams must be handled asynchronously. You need to modify the code as follows:
export async function getBlogFromParams(
params: BlogPageProps["params"],
searchParams: BlogPageProps["searchParams"]
) {
const parameters = await params;
const slug = parameters?.slug?.join("/");
// find blog by params and return it
}
type BlogPageProps = {
params: Promise<{
slug: string[];
}>;
searchParams: Promise<{
[key: string]: string | string[] | undefined;
}>;
};
And it even explains why it was changed to this Promise method.
Why these changes are necessary:
1. Next.js 15 handles searchParams asynchronously for performance optimization.
2. This enables more efficient data loading in server components.
3. All searchParams access must use await.
Please also check the following:
- If there are other parts that use searchParams, you need to modify them in the same way.
- This change is one of the major changes in Next.js 15.
- This is a change to improve the performance of server components.
It seems that the Param part, which is processed when a page is processed dynamically, has been changed to an asynchronous method.
I don't know the clear reason and background, but when I changed it as above, the server error log disappeared. There were a few other server components that operated in a Dynamic Route method besides BlogPage, so I modified them in the same way. And when I tested other pages, no problems occurred.
So, I performed the build through the npm run build
command and confirmed that no error logs were printed at all. I pushed the changed code to the main branch and proceeded with the deployment.
Everything was finished without any problems! 🤓
Cause of the Server Error Log
After the upgrade was completed so smoothly, I wanted to understand the root cause of the only error that occurred. If you look closely at the error log again, it guides you to visit https://nextjs.org/docs/messages/sync-dynamic-apis.
If you access the page, it explains the cause of the error.

There is a component somewhere in the module that uses Dynamic API (ex: params
, searchParams
) to perform Dynamic rendering, and it seems that the operation method of this Dynamic API has changed to asynchronous.
But I couldn't find out exactly why
it was changed.
Really, Why Was It Changed?
The answer was in the Next.js 15 release document (https://nextjs.org/blog/next-15#async-request-apis-breaking-change)
And with the help of Googling and Claude and ChatGPT, I was able to summarize Why
as follows:
- In the case of Server Side Rendering (SSR), Dynamic API is used when processing request-specific data.
- Until v15, these Dynamic APIs worked synchronously.
- However, not all elements of the component depend on this Dynamic API call data, so what can be prepared as much as possible before the request arrives at the server should be able to be prepared.
- As Dynamic APIs are switched to asynchronous in v15, some components can be pre-rendered to improve the overall performance of the application (streaming some data first as it becomes available).
- Also, since server components basically operate in an asynchronous manner, changing the way APIs operate from synchronous to asynchronous can be seen as more in line with this paradigm.
In other words, the BlogPage
component that was problematic uses Dynamic API for Dynamic rendering. Therefore, it was affected by upgrading to Next.js v15. (However, although not explained above, the BlogPage component has a generateStaticParams function inside, so it is pre-rendered at build time and actually deployed and operates with Static rendering.)
After checking up to here, I understood to some extent, so I finished the Next.js v15 upgrade work here.
References and Videos
- https://nextjs.org/blog/next-15#async-request-apis-breaking-change
- https://www.youtube.com/watch?v=bMOwKsidqJ0
- https://medium.com/@codified_brain/next-js-15-handling-async-request-apis-with-practical-examples-9aa4af21b664
Is This the End?
However, there were a few things that bothered me.
-
Since I am not fully aware of Next.js's many rendering methods, I did not clearly understand exactly why the asynchronous transition of Dynamic API is advantageous in terms of rendering performance.
-
If you look at the Next.js v15 official document, there were some things that were newly added or became Stable versions due to this version.
- React 19
- Turbopack Dev (Stable)
I hope to have the opportunity to summarize and share these concepts in a blog post in the future.
Then thank you for reading to the end!
Comments (0)
Checking login status...
No comments yet. Be the first to comment!