Nuxt 4 у 2026 році: Нова структура каталогів та міграція з Nuxt 3
Повний посібник з міграції на Nuxt 4: нова структура app/, singleton-шар отримання даних, поверхнева реактивність за замовчуванням, розділення TypeScript-контексту, нормалізовані імена компонентів, Vue Router v5, зміни в управлінні head та контрольний список міграції.

Nuxt 4 являє собою найбільше архітектурне оновлення фреймворку з моменту виходу третьої версії. Нова структура каталогу app/, singleton-модель отримання даних, поверхнева реактивність за замовчуванням та розділений TypeScript-контекст змінюють підхід до організації й супроводу Vue-застосунків. Для розробників, які працюють з екосистемою Vue та Nuxt, глибоке розуміння цих змін є критично важливим як для повсякденної роботи, так і для підготовки до технічних співбесід. У цьому матеріалі розглядається кожна ключова зміна Nuxt 4 з практичними прикладами коду та покроковими інструкціями щодо міграції з Nuxt 3.
Nuxt 4 надає офіційний codemod для автоматичної реструктуризації каталогів. Перед початком ручної міграції варто запустити npx codemod@latest nuxt/4/file-structure, який автоматизує більшу частину структурних змін. Проте оновлення composable, конфігурація TypeScript та управління мета-тегами потребують ручного втручання.
Нова структура каталогу app/
Найпомітніша зміна в Nuxt 4 полягає у переміщенні всіх клієнтських та серверних файлів застосунку до спеціалізованого каталогу app/. У Nuxt 3 компоненти, сторінки, лейаути, middleware та плагіни розміщувалися безпосередньо в кореневому каталозі проєкту. Nuxt 4 чітко розмежовує код застосунку від конфігураційних файлів, публічних ресурсів та серверного коду.
my-nuxt-app/
├─ app/
│ ├─ assets/
│ ├─ components/
│ ├─ composables/
│ ├─ layouts/
│ ├─ middleware/
│ ├─ pages/
│ ├─ plugins/
│ ├─ utils/
│ ├─ app.vue
│ ├─ app.config.ts
│ └─ error.vue
├─ content/
├─ public/
├─ shared/ # New: code shared between app and server
├─ server/
└─ nuxt.config.tsНовий каталог shared/ є важливим архітектурним доповненням. Він дозволяє спільно використовувати типи, допоміжні функції та константи між кодом застосунку (app/) і серверним кодом (server/). У Nuxt 3 розробники змушені були дублювати типи на обох сторонах або створювати тимчасові рішення з відносними шляхами імпорту. Каталог shared/ вирішує цю проблему на структурному рівні, забезпечуючи єдине джерело істини для спільного коду.
Файл nuxt.config.ts залишається в кореневому каталозі проєкту й не переміщується до app/. Аналогічно, каталоги server/ та public/ зберігають свої поточні розташування. Це розмежування чітко визначає зони відповідальності: app/ містить код, що виконується у браузері та на SSR-сервері, server/ зберігає бекенд-логіку, а shared/ слугує мостом між цими двома шарами.
Покрокова міграція з Nuxt 3
Процес міграції з Nuxt 3 на Nuxt 4 складається з кількох послідовних етапів. Першим кроком є оновлення фреймворку до останньої версії та дедуплікація залежностей.
# Upgrade Nuxt and deduplicate dependencies
npx nuxt upgrade --dedupeДалі запускається офіційний codemod, який автоматично реструктурує файлову систему відповідно до нового стандарту. Codemod переносить файли до каталогу app/, оновлює шляхи імпорту та адаптує конфігурацію.
# Automate the directory restructuring
npx codemod@latest nuxt/4/file-structureДля проєктів, які не можуть одразу перейти на нову структуру каталогів, Nuxt 4 пропонує опцію зворотної сумісності. Налаштування srcDir та dir.app у конфігурації дозволяє зберегти плоску структуру під час поступового переходу.
export default defineNuxtConfig({
srcDir: '.',
dir: { app: 'app' },
})Однак це тимчасове рішення. Команда Nuxt однозначно рекомендує повний перехід на структуру app/, оскільки майбутні версії фреймворку оптимізуватимуться саме під цю організацію. Крім того, інструменти екосистеми, зокрема Nuxt DevTools та модулі спільноти, вже починають приймати нову структуру як стандартну.
Singleton-шар отримання даних та реактивні ключі
Nuxt 4 вносить фундаментальну зміну в роботу composable useAsyncData та useFetch. У Nuxt 3 виклик одного й того ж ключа даних з різних компонентів міг спричинити дублювання мережевих запитів та неузгодженість стану. Nuxt 4 впроваджує singleton-патерн: кожен унікальний ключ даних пов'язується рівно з одним екземпляром отримання даних, незалежно від кількості компонентів, що використовують ці дані.
Додатково useAsyncData отримує новий параметр getCachedData з контекстним об'єктом ctx, який повідомляє причину повторного виклику. Це дає змогу точно контролювати, коли використовувати кешовані дані, а коли виконувати новий запит.
export function useProductData(productId: string) {
return useAsyncData(
`product-${productId}`,
() => $fetch(`/api/products/${productId}`),
{
getCachedData: (key, nuxtApp, ctx) => {
// ctx.cause tells why the fetch is happening
if (ctx.cause === 'refresh:manual') return undefined
return nuxtApp.payload.data[key]
},
},
)
}Параметр ctx.cause може набувати значень 'refresh:manual' (ручне оновлення, ініційоване розробником), 'refresh:hook' (оновлення, ініційоване хуком життєвого циклу) або 'navigation' (навігація між сторінками). Завдяки цьому composable може приймати обгрунтовані рішення щодо стратегії кешування: наприклад, завжди використовувати кеш при навігації, але примусово виконувати запит при ручному оновленні.
Singleton-патерн також усуває стани перегонів (race conditions). Коли кілька компонентів одночасно запитують однакові дані, Nuxt 4 виконує лише один запит і розподіляє результат між усіма підписниками. Такий підхід зменшує мережеве навантаження та забезпечує узгодженість даних у всьому застосунку.
Поверхнева реактивність за замовчуванням
Одна з найвпливовіших змін у Nuxt 4 полягає в тому, що дані, повернуті useAsyncData та useFetch, за замовчуванням обгортаються у shallowRef замість ref. У Nuxt 3 використовувалася глибока реактивність, а це означало, що будь-яка зміна вкладених властивостей об'єкта автоматично ініціювала оновлення компонента. У Nuxt 4 повторний рендер відбувається лише при повній заміні значення value.
<script setup lang="ts">
// Data is now a shallowRef by default
const { data: metrics } = await useFetch('/api/dashboard/metrics')
// Direct property mutation won't trigger reactivity
// metrics.value.visits = 100 // Won't trigger re-render
// Replace the entire value to trigger updates
metrics.value = { ...metrics.value, visits: 100 }
// Or opt into deep reactivity for this specific call
const { data: settings } = await useFetch('/api/settings', {
deep: true,
})
</script>Ця зміна має прямий вплив на продуктивність. Глибока реактивність створює проксі для кожного вкладеного об'єкта та масиву, що спричиняє значне навантаження на пам'ять та процесор при роботі з великими структурами даних. Поверхнева реактивність повністю усуває ці витрати, оскільки система реактивності Vue відстежує лише посилання верхнього рівня.
Для команд, що мігрують з Nuxt 3, це означає необхідність перевірки всіх ділянок коду, де вкладені властивості даних, отриманих через useFetch або useAsyncData, змінюються безпосередньо. Кожну таку мутацію потрібно замінити повною заміною значення (через spread-оператор) або явним увімкненням глибокої реактивності за допомогою опції deep: true.
Готовий до співбесід з Vue.js / Nuxt.js?
Практикуйся з нашими інтерактивними симуляторами, flashcards та технічними тестами.
Розділення TypeScript-контексту (Context Splitting)
Замість єдиного глобального tsconfig.json Nuxt 4 розділяє конфігурацію TypeScript на чотири окремі контексти. Кожен контекст має власні правила розв'язання типів, що усуває проблему видимості серверних типів у клієнтському коді та навпаки.
{
"files": [],
"references": [
{ "path": "./.nuxt/tsconfig.app.json" },
{ "path": "./.nuxt/tsconfig.server.json" },
{ "path": "./.nuxt/tsconfig.shared.json" },
{ "path": "./.nuxt/tsconfig.node.json" }
]
}Контекст app охоплює код у каталозі app/, включаючи компоненти, сторінки та composable. Контекст server обслуговує файли в каталозі server/ з доступом до типів Node.js та серверних API. Контекст shared забезпечує підтримку типів для каталогу shared/, видимих як з app, так і з server. Контекст node покриває конфігураційні файли, зокрема nuxt.config.ts.
Це розділення вимагає зміни способу запуску перевірки типів. Прапорець -b (режим компіляції проєктних посилань) для vue-tsc стає обов'язковим.
# Before (Nuxt 3)
nuxt prepare && vue-tsc --noEmit
# After (Nuxt 4)
nuxt prepare && vue-tsc -b --noEmitБез прапорця -b компілятор TypeScript не розпізнає міжпроєктні посилання й повідомлятиме про помилки відсутніх типів. Це одна з найчастіше пропущених змін під час міграції, яка призводить до збоїв у CI/CD-конвеєрах.
Нормалізовані імена компонентів та Vue Router v5
Nuxt 4 змінює правила іменування автоматично імпортованих компонентів. Компоненти у підкаталогах тепер отримують імена на основі повного шляху каталогу, а не лише імені файлу. Наприклад, компонент components/dashboard/MetricsCard.vue у Nuxt 3 був доступний як DashboardMetricsCard або MetricsCard. У Nuxt 4 дійсним є лише повне нормалізоване ім'я.
Ця зміна безпосередньо впливає на конфігурацію <KeepAlive>, де імена компонентів мають бути явно вказані у масивах include або exclude.
<!-- app/pages/dashboard.vue -->
<template>
<NuxtPage :keepalive="{
include: ['DashboardMetricsCard', 'DashboardRecentActivity'],
}" />
</template>Необхідно перевірити імена компонентів, використані в keepalive, <Transition> та динамічних компонентах (<component :is="...">), на відповідність новим нормалізованим іменам. Інакше KeepAlive припинить кешування компонентів, а анімовані переходи перестануть працювати.
Паралельно з цим Nuxt 4 інтегрує Vue Router v5, який вносить зміни в API навігації та механізми навігаційних гардів. Метод router.resolve() тепер повертає розширений об'єкт з додатковими метаданими. Навігаційні гарди отримали покращену типізацію параметрів. Командам, що використовують складні патерни маршрутизації, необхідно перевірити сумісність своїх гардів та middleware з новим API.
Критичні зміни в управлінні head (Unhead v2)
Nuxt 4 переходить на Unhead v2, що вносить критичні зміни в управління мета-тегами та елементами <head>. Властивості vmid, hid, children та body, які використовувалися в Nuxt 3 для визначення й дедуплікації тегів, видалено.
<script setup lang="ts">
const route = useRoute()
const { data: product } = await useFetch(`/api/products/${route.params.id}`)
// Unhead v2: removed vmid, hid, children, body props
useSeoMeta({
title: () => product.value?.name ?? 'Product',
ogTitle: () => product.value?.name ?? 'Product',
description: () => product.value?.description ?? '',
ogImage: () => product.value?.imageUrl ?? '',
})
</script>Окрім того, деякі плагіни Unhead, зокрема TemplateParamsPlugin та AliasSortingPlugin, більше не завантажуються за замовчуванням. Якщо проєкт використовує шаблонні параметри у мета-тегах (наприклад, %s | Назва сайту), їх необхідно явно зареєструвати як Nuxt-плагін.
import { TemplateParamsPlugin, AliasSortingPlugin } from '@unhead/vue/plugins'
export default defineNuxtPlugin({
setup() {
const unhead = injectHead()
unhead.use(TemplateParamsPlugin)
unhead.use(AliasSortingPlugin)
},
})Симптом відсутньої реєстрації цих плагінів є досить підступним: шаблони заголовків не обробляються, і користувач бачить необроблений текст із символами %s замість сформованого заголовка. Ця проблема може не впливати на роботу застосунку в середовищі розробки, тому її складно виявити, поки не буде проаналізовано SEO-метрики в Google Search Console.
Контрольний список міграції та типові пастки
Нижче наведено повний контрольний список для команд, що мігрують з Nuxt 3 на Nuxt 4. Кожен пункт має бути перевірений та підтверджений перед розгортанням у виробниче середовище.
- Оновлення Nuxt -- запуск
npx nuxt upgrade --dedupeта перевірка сумісності всіх залежностей з Nuxt 4 - Реструктуризація каталогів -- запуск codemod або ручне переміщення файлів до каталогів
app/,shared/таserver/ - Перевірка шляхів імпорту -- контроль оновлення всіх шляхів імпорту після переміщення файлів
- Оновлення composable отримання даних -- перегляд усіх використань
useAsyncDataтаuseFetchз урахуванням нового APIgetCachedDataта singleton-патерну - Адаптація до shallow reactivity -- виявлення та виправлення всіх місць, де вкладені властивості даних змінюються безпосередньо
- Конфігурація TypeScript -- оновлення
tsconfig.jsonдо формату проєктних посилань та перехідvue-tscна режим-b - Імена компонентів -- перевірка відповідності імен у
keepalive,<Transition>та динамічних компонентах новим нормалізованим іменам - Мета-теги (Unhead v2) -- видалення застарілих властивостей (
vmid,hid,children,body) та реєстрація необхідних плагінів - E2E-тести -- запуск повного набору наскрізних тестів з урахуванням змін навігації Vue Router v5
- CI/CD-конвеєр -- оновлення команд збірки та перевірки типів у конфігурації конвеєра
Найтиповіші пастки під час міграції:
- Забуті мутації shallowRef -- код виду
data.value.property = x, що безпосередньо змінює вкладені властивості, не ініціює повторний рендер. Це найчастіше повідомлювана проблема після міграції - Відсутній прапорець
-b-- пропуск-bу командіvue-tscспричиняє хибні помилки типів, які не видно локально, але з'являються в CI - Ненормалізовані імена у KeepAlive -- KeepAlive мовчки ігнорує нерозпізнані імена, що призводить до втрати кешування без видимої помилки
- Відсутні плагіни Unhead -- непрацюючі шаблони заголовків перетворюються на SEO-проблему, яку можна виявити лише при аналізі результатів Google Search Console
Для поглиблення знань з екосистеми Vue та Nuxt рекомендується звернутися до питання для співбесіди Vue/Nuxt та посібник з SSR та статичної генерації.
Висновки
Nuxt 4 є значним кроком в еволюції фреймворку, що вносить зміни на кожному рівні процесу розробки. Основні висновки для підготовки до міграції та технічних співбесід:
- Нова структура каталогу
app/чітко відокремлює код застосунку від конфігурації та серверних ресурсів; каталогshared/усуває дублювання типів між клієнтом та сервером - Singleton-шар отримання даних забезпечує точний контроль над стратегією кешування через патерн
getCachedDataта контекстний об'єктctx, запобігаючи дублюванню мережевих запитів - Поверхнева реактивність за замовчуванням суттєво підвищує продуктивність для великих структур даних, однак вимагає свідомої адаптації коду, що змінює вкладені властивості
- Розділений TypeScript-контекст забезпечує строгу ізоляцію типів між клієнтським, серверним та спільним кодом, усуваючи цілий клас типових помилок
- Нормалізовані імена компонентів та інтеграція Vue Router v5 вимагають перегляду конфігурації KeepAlive, анімованих переходів та навігаційних гардів
- Unhead v2 зобов'язує явно реєструвати шаблонні плагіни та очищати застарілі властивості мета-тегів
- Офіційний codemod автоматизує реструктуризацію каталогів, проте зміни у composable, TypeScript та мета-тегах потребують ручної перевірки та адаптації
Починай практикувати!
Перевір свої знання з нашими симуляторами співбесід та технічними тестами.
Теги
Поділитися
Пов'язані статті

Vue 3 Pinia vs Vuex: Сучасне управління станом та питання для співбесід 2026
Порівняння Pinia та Vuex: архітектура, TypeScript, Composition API, міграція, гідратація SSR та найпоширеніші питання зі співбесід щодо управління станом Vue у 2026 році.

Nuxt 3: SSR і статична генерація, повний посібник
Опанувати SSR і статичну генерацію з Nuxt 3. Від useFetch до route rules: як оптимізувати продуктивність застосунків Vue.js.

Ключові запитання співбесід із Vue.js: 25 запитань, щоб отримати роботу
Підготуйтеся до співбесід із Vue.js, маючи в арсеналі 25 ключових запитань. Від реактивності до composables — опануйте найважливіше для наступної зустрічі.