Nuxt v4 is coming out soon. This version of Nuxt is predominantly about performance upgrades and API consistency. Although there are no ground-breaking user-facing changes, we’ll still go through them one by one in this tutorial to make sure your Nuxt v3 app can still run on v4.
At the time of this writing, nuxt v4 has not been released yet. But you can still try it out using v3.12.
First, upgrade the Nuxt version in your app:
npx nuxi@latest upgrade
This will upgrade your project to the latest Nuxt version.
With v3.12, you have to set the compatibilityVersion
option to 4
:
nuxt.config.ts
export default defineNuxtConfig({
future: {
compatibilityVersion: 4
},
...
})
Next, let’s talk about the changes you should be expecting in Nuxt 4.
Nuxt 4 Folder Structure
The most obvious change in Nuxt v4 is the new folder structure:
Now you have to put the client-side code in the app folder instead of the root folder. But the server folder can stay where it is.
This change would require you to move some of your files around, but this change is optional. If you don’t do it, Nuxt can still detect it and use the old way.
This is a performance upgrade because the file watchers don’t have to watch all the files in the root folder. Secondly, this is also a DX upgrade because IDEs can provide better support with client code and server code separated in their own folders. For instance, server code is usually running in a Node.js environment, and the client code is running in a browser environment. Separating the two different types of code means that the IDE can be configured for each folder separately.
useAsyncData & useFetch
There are a handful of miscellaneous changes with useAsyncData
and useFetch
that you need to be mindful of.
First of all, the data fetched using useAsyncData
and useFetch
will be cached and made available to other pre-rendered pages without refetching.
This data-sharing feature has been experimental, but in Nuxt 4, it’s a real feature.
The data ref that gets returned will now be a shallow ref:
(Shallow ref will only be reactive if the .value
itself is reassigned.)
Both of these composables also return a refresh
function that you can call to refetch the data. And this refresh
function can be configured with a dedupe
option:
Instead of using true
and false
, now you have to use cancel
or defer
to set the dedupe
option. Cancel means cancelling the duplicated request (the new one), and defer means wait for the existing one to finish before executing the new one.
When useAsyncData
is configured with a default value, refreshNuxtData
will reset the data back to that default value:
(Previously, this would reset the comments
to undefined
. And since useFetch
couldn’t be configured with a default value, this doesn’t affect useFetch
.)
On a related note, if you didn’t set a default value, it will now default to undefined
. This applies to both useAsyncData
and useFetch
:
(Previously, it defaults to null
.)
Other Nuxt 4 Changes
Finally, there are changes that don’t affect most projects so you probably don’t need to worry about them. But I include them here for completeness:
- Now Nuxt scans the index.js files in the child folders inside /middleware.
- Now the
builder:watch
hook emits an absolute path, instead of a relative path. - Some template-specific code generation utils have been removed, and .ejs file compilation is removed, too.
- Some experimental features have also been removed, so their corresponding config options have been removed too:
treeshakeClientOnly
,configSchema
,polyfillVueUseHead
,respectNoSSRHeader
.
Where to go next?
From a framework user standpoint, Nuxt 3 and Nuxt 4 are basically the same Nuxt. You can think of Nuxt 4 as a more fleshed out version of Nuxt 3. This is great because you can still use most of the Nuxt 3 learning materials currently available.
If you enjoy visually illustrated content like this tutorial, you should check out the Real World Nuxt course and the Nuxt API Routes course here on VueMastery.com.