Nuxt 4.5 — крупный релиз. В нём три апгрейда сборщика (Vite 8, Rspack 2 и новый pipeline на Rsbuild для Rspack builder), экспериментальный SSR streaming, стабильная система кодов ошибок, несколько новых composables и соглашений, плюс работа, которая приближает Nuxt 5.
Много изменений — самое время заварить кофе. ☕️
📣 Новости
Подготовка к Nuxt 5
Заметная часть релиза — (надеемся) невидимая инфраструктура для Nuxt 5. Мы перешли на последние major-версии ряда ключевых зависимостей (unhead v3, unctx v3 и Vite 8), перевели сборку самого фреймворка на tsdown и ввели стабильный контракт выходной сборки nuxt/* с dev-экспортами, чтобы type-checking в monorepo Nuxt работал без шага сборки (#35463, #35605).
Большая часть работы сужает внутренний разрыв между v4 и v5, чтобы миграция была максимально скучной(?).
future.compatibilityVersion: 5. Следите за Upgrade Guide — там появятся детали.С выходом Nuxt v4.5 команда сосредоточится на стабилизации Nuxt v5 и утилитах совместимости для плавного апгрейда.
Конец поддержки Nuxt 3
Nuxt 3 выходит из поддержки 31 июля 2026 — это один из последних релизов линейки 3.x. Если вы всё ещё на v3, самое время переехать. Большинство назвали переход с v3 на v4 гладким, а upgrade guide мы держим актуальным.
Вместе с v4.5.0 выходит патч для линейки 3.x (v3.21.9) с совместимыми исправлениями и мелкими улучшениями из этого релиза. Ключевые пункты (Vite 8, Rspack 2, unhead v3, unctx v3) — крупные апгрейды и остаются только в v4, поэтому 3.x сохраняет стабильность до конца поддержки.
⚡️ Vite 8
Nuxt теперь работает на Vite 8 (#34256). Холодный старт быстрее, внутренности на Rolldown свежее, плюс апстрим-улучшения от команды Vite.
Для большинства приложений апгрейд прозрачен. Если у вас кастомные Vite-плагины или конфиг, загляните в Vite migration guide — вдруг что-то затронет вас.
vite.config или экосистемные плагины с фиксированной версией Vite), проверьте совместимость до продакшена.🦀 Rspack 2 и Rsbuild
Если вы используете Rspack builder, этот релиз — существенный апгрейд. Мы перешли на Rspack 2 (#34929): быстрее, легче, и builder пересобран поверх @rsbuild/core (#35489).
Публичный API тот же. Подключение — builder: 'rspack', хуки rspack:* работают как раньше:
export default defineNuxtConfig({
builder: 'rspack',
})
Под капотом многое улучшилось:
- Dev-сервер теперь в middleware mode через Rsbuild вместо
webpack-dev-middlewareиwebpack-hot-middleware(#35575). - Для SSR scoped-style ids и строгого ESM resolution используется Rspack-специфичный Vue loader (#35566).
rspack, чтобы ничего не сломать, но внутри всё построено на Rsbuild.🌊 Экспериментальный SSR Streaming
Это одна из фич, которая меня радует больше всего. Можно включить SSR streaming и сильно улучшить Time to First Byte (#34411). Вместо буферизации всей страницы Nuxt сразу отдаёт HTML-оболочку (<head>, стили, preload hints, entry scripts), а body стримит по мере рендера Vue.
export default defineNuxtConfig({
experimental: {
ssrStreaming: true,
},
})
Streaming автоматически отключается для ботов и краулеров, чтобы поисковики получали полностью отрендеренный HTML. Можно настроить user agents, считающиеся краулерами, и отключить streaming для отдельных маршрутов:
export default defineNuxtConfig({
experimental: {
ssrStreaming: {
botRegex: /googlebot|bingbot|my-internal-crawler/i,
},
},
routeRules: {
'/no-stream/**': { streaming: false },
},
})
Перед включением стоит понять одну вещь. Streaming фиксирует HTTP-статус и заголовки с первым байтом, поэтому всё, что меняет ответ после начала рендера (setResponseStatus() в <script setup>, запись cookie в middleware и т.д.), до клиента не дойдёт. Nuxt закрывает типичные случаи: маршруты с правилами redirect, cache, isr, swr, noScripts или ssr: false автоматически откатываются на buffered renderer, а в dev мы логируем предупреждение о пропущенных мутациях, чтобы ничего не терялось молча.
🩺 Стабильные коды ошибок
Меня это особенно радует. В Nuxt появилась стабильная система кодов ошибок (#35429) на nostics. Предупреждения и ошибки при сборке и в runtime теперь несут стабильный код (например NUXT_E1001 или NUXT_B5001), короткое объяснение почему это случилось, и конкретный fix.
Каждый код можно grep'ить и bookmark'ить; сложные случаи ведут на отдельную страницу доков. Классическая «composable вызвана вне Nuxt context» теперь — NUXT_E1001 с why/fix inline и docs page про правила context и runWithContext().
В продакшене verbose why/fix убирается, остаётся только стабильный код.
Это основа для гораздо лучших сообщений об ошибках; в следующих релизах будем переносить на неё существующие warnings и errors. 🔥
🎨 Composable useLayout
Новый composable useLayout читает layout, выбранный для текущего маршрута (#35623). Раньше не было чистого реактивного способа спросить из компонента «какой layout у этой страницы?».
<script setup lang="ts">
const layout = useLayout()
</script>
<template>
<span>Current layout: {{ layout }}</span>
</template>
Возвращает read-only computed ref: значение синхронизируется при навигации и когда route rules или definePageMeta меняют resolved layout.
🪟 Именованные views
Nuxt поддерживает named views через соглашение об именах файлов (#35123). Если родительская страница рендерит больше одного <NuxtPage>, каждому outlet можно дать имя и положить sibling-файл по соглашению name@view.vue:
-| pages/
---| parent/
-----| child.vue
-----| child@sidebar.vue
---| parent.vue
<template>
<div>
<NuxtPage />
<aside>
<NuxtPage name="sidebar" />
</aside>
</div>
</template>
При переходе на /parent/child child.vue попадает в default outlet, а child@sidebar.vue — в sidebar. В Vue Router это было давно; в этом релизе мы связали это с file-based routing Nuxt.
definePageMeta читается только из default route file, per-view rendering modes не поддерживаются (режим родительской страницы применяется к default view).🚦 Опция enabled для useFetch и useAsyncData
Теперь можно блокировать fetch реактивной опцией enabled (#33260). Пока enabled равен false, каждый запуск блокируется (начальный fetch, execute/refresh, watch triggers). Если переключить с true на false во время запроса, in-flight request отменяется без очистки существующих data.
<script setup lang="ts">
const query = ref('')
const { data } = await useFetch('/api/search', {
query: { q: query },
// Only fetch once the user has typed something
enabled: () => query.value.length > 2,
})
</script>
Удобно для зависимых или условных запросов, когда request не должен уходить, пока не выполнено условие. Работает с getter или ref и остаётся реактивным.
🔗 Prefetch для NuxtLink с custom slots
Если вы используете <NuxtLink> с prop custom, Nuxt больше не вешает prefetch handlers сам: он не знает, как устроена ваша разметка. Slot теперь отдаёт всё нужное для ручного prefetch (#34539):
<template>
<NuxtLink
v-slot="{ href, navigate, prefetch, prefetched, shouldPrefetch }"
to="/about"
custom
>
<a
:href="href"
:class="{ 'is-prefetched': prefetched }"
@click="navigate"
@pointerenter="shouldPrefetch('interaction') && prefetch()"
@focus="shouldPrefetch('interaction') && prefetch()"
>
About page
</a>
</NuxtLink>
</template>
prefetch запускает prefetch, prefetched показывает, что он уже был (удобно для класса prefetched), shouldPrefetch учитывает соединение пользователя и конфиг.
⚡️ Forwarded Preload Hints при Prefetch
Попробуйте и эту опцию. При prefetch ссылки на маршрут с payload extraction Nuxt уже подгружает data и chunks назначения. С opt-in experimental.prefetchPreloadTags (#35144) он также пробрасывает <link rel="preload"> и modulepreload hints назначения (что страница задаёт через useHead или модули вроде <NuxtImg preload> из @nuxt/image) в текущий document, понижая до rel="prefetch", чтобы они не конкурировали с ресурсами текущей страницы.
export default defineNuxtConfig({
experimental: {
prefetchPreloadTags: true,
},
})
На практике тяжёлые above-the-fold ресурсы следующей страницы (hero image, critical script) начинают качаться, пока пользователь ещё на текущей, и навигация ощущается мгновенной. По умолчанию выключено, пока собираем feedback — попробуйте и расскажите, как ведёт себя в вашем приложении.
🌐 import.meta.envName
Resolved Nuxt environment name теперь доступен в runtime как import.meta.envName для Vite и webpack/Rspack builds (#34844). Это значение из --envName (или resolved default), по нему можно ветвиться в коде приложения:
if (import.meta.envName === 'staging') {
// enable staging-only behaviour
}
🔭 Tracing channels для SSR-событий
Nuxt публикует diagnostics-channel traces для server-side подсистем (#35191). Мы не навязываем стек: эмитим каналы nuxt.render, nuxt.island, nuxt.data и nuxt.plugin по соглашению untracing, поверх можно строить OpenTelemetry или что угодно ещё. Работает в Node, Deno, Bun и Cloudflare Workers.
export default defineNuxtConfig({
// Turn on Nuxt's own channels
tracingChannel: true,
})
Можно включать точечно. В Nuxt v5 появятся дополнительные Nitro-level channels:
export default defineNuxtConfig({
tracingChannel: {
nuxt: true,
},
})
📦 Обновления зависимостей
unhead v3
Head management в Nuxt теперь на unhead v3 (#34793). Меньше размер, синхронный engine внутри, лучше type-safety для useHead из коробки. Это также разблокирует SSR streaming.
unhead v3 сужает типы для useHead — breaking type change, если вы опирались на более мягкие типы v2. Runtime для подавляющего большинства приложений совместим; promise input (deprecated в v2) больше не поддерживается. Ошибки типов после апгрейда почти всегда означают реальное ужесточение, а не регрессию.unctx v3
Мы перешли на unctx v3 (#35541), что закрывает класс давних async context issues (#33644). Это часть работы над надёжностью composable context, которая продолжится в v5.
И ещё
Обновили magic-string до v1, Babel до v8 и подтянули последний Rolldown повсюду. nuxt upgrade --dedupe (см. ниже) — самый простой способ аккуратно подтянуть всё это.
🛠️ Nuxt CLI
В релизе улучшения из @nuxt/cli v3.36 и v3.37:
nuxt module removeудаляет модуль и чистит его конфиг (nuxt/cli#1306), пара кnuxt module add.- Non-interactive
nuxt initдля скриптов и CI (nuxt/cli#1341); больше не спрашивает package manager, берёт его из шаблона (nuxt/cli#1330). - Онбординг type-check:
nuxt typecheckпредложит установитьvue-tscиtypescript, если их нет (nuxt/cli#1316). - Поддержка Golar для type-checking:
nuxt typecheckможет использовать Golar вместоvue-tsc(nuxt/cli#1362). Подхватывается автоматически, если Golar установлен (или естьgolar.config.*); checker можно задать явно:--checker=vue-tscили--checker=golar:nuxt typecheck --checker=golar - Dev server с учётом layers: dev server перезагружается при изменениях
nuxt.configв локальных layers (nuxt/cli#1345).
🧩 TypeScript Plugin и Named Layout Slots
Экспериментальный TypeScript plugin Nuxt работает на @dxup/nuxt, в релизе — более новая версия. Если не пробовали: experimental.typescriptPlugin даёт удобства в редакторе — переименование auto-imported component обновляет все использования, плюс go-to-definition для glob imports, Nitro routes, definePageMeta, runtimeConfig и typed route names.
В bundled версии появилась opt-in runtime фича: named layout slots (KazariEX/dxup#20). Можно написать top-level named-slot template на странице, и он попадёт в matching named slot активного layout. Страница сможет вставлять контент в slots layout — file-based layouts иначе этого не дают.
Включите вместе с plugin:
export default defineNuxtConfig({
experimental: {
typescriptPlugin: true,
},
dxup: {
features: {
namedLayoutSlots: true,
},
},
})
Layout может объявить named slots:
<template>
<slot />
<slot name="side" one="one" />
</template>
Любая страница с этим layout заполняет их:
<script setup lang="ts">
definePageMeta({ layout: 'center' })
</script>
<template>
<template #side="{ one }">
This "{{ one }}" comes from the layout slot.
</template>
<div>About page</div>
</template>
🔥 Производительность и надёжность
Как всегда, много работы ушло в скорость и стабильность.
Одна опция, которую можно включить уже сейчас: shared file watcher (#35143). Vite уже крутит chokidar-based watcher, и Nuxt может использовать его вместо второго — меньше памяти, меньше file handles. С compatibilityVersion: 5 это станет default, но включить можно сейчас:
export default defineNuxtConfig({
experimental: {
watcher: 'builder',
},
})
Есть и улучшения без opt-in:
- Быстрее старт dev-сервера – dev-only Nitro и pages work отложены и упрощены (#35381, #35383).
- Легче production-сборки – island-renderer chunk не попадает в сборку без islands (#35456), plugin handling вырезается из prod builds (#35278).
- Улучшенный island hashing – стабильнее island и key hashing;
getIslandHashиhashKeyтеперь exposed (#35583). - Выигрыш по concurrency и I/O в Kit path resolution и Nitro inline styles (#35511, #35514).
Ещё пара quality-of-life fixes:
$fetchauto-imported в user code — закрывает edge cases с top-level$fetch.createпод Rolldown output format (#35581).- Nuxt учитывает системные
HTTP_PROXY/HTTPS_PROXYв builder environment (#35183). - HMR работает для
defineNuxtComponentв JSX (#35620).
⚠️ На что обратить внимание перед апгрейдом
Как выше, в релизе три major dependency bumps. Для большинства приложений они прозрачны, но стоит проверить:
- Vite 8 – сверьте кастомные Vite plugins и конфиг с Vite migration guide.
- Rspack 2 – при
builder: 'rspack'внутренности теперь на Rsbuild; кастомный Rspack config может потребовать правок. unheadv3 – возможные breaking type changes из-за более строгой типизацииuseHead.
⬆️ Обновление
Рекомендуем апгрейд так:
npx nuxt upgrade --dedupe
# or, if you are staying on the 3.x line
npx nuxt@latest upgrade --dedupe --channel=v3
Команда deduplicate lockfile и подтягивает обновления зависимостей Nuxt, особенно в unjs ecosystem (в этом релизе это важнее обычного из-за major bumps).
👉 Полные release notes
Спасибо всем, кто внёс вклад в этот релиз. Он получился большим, и без вас его бы не было. 💚