Nuxt 4: New Directory Structure and Migration Guide
Table of contents
- 🧭 Quick Navigation Guide
- 🔄 Nuxt 3 vs Nuxt 4 Comparison
- Old Framework (Nuxt 3)
- New Framework (Nuxt 4)
- 🎯 Benefits of the New Structure
- 1. Best File Watching Performance
- 2. Clear Separation of Responsibilities
- 3. Best Organization for Large Projects
- 🚀 Automatic Migration
- Using the Upgrade Command
- What the Command Does Automatically
- 🔧 Manual Migration
- Step by step
- Update Imports
- ⚙️ Nuxt 4 Configuration
- Basic Configuration
- Advanced Configuration
- 💡 Practical Examples
- Example of Optimized Organization
- Project Structure Example
- 🚨 Common Problems and Solutions
- 1. Broken Imports
- 2. Assets Not Found
- 3. Build Settings
- 🔍 Migration Check
- Verification Checklist
- Verification Commands
- 🎯 Next Steps
- ✨ Conclusion
Nuxt 4 brings one of the most significant changes in its history: a complete reorganization of the directory structure. The new structure with the app/ directory is not just a cosmetic change - it is an architectural redesign that improves the performance, organization and scalability of projects.
🧭 Quick Navigation Guide
🏗️ Structure and Organization
- Nuxt 3 vs Nuxt 4 Comparison
- Benefits of the New Structure
- Automatic Migration
- Manual Migration
- Nuxt 4 Configuration
- Practical Examples
🔄 Nuxt 3 vs Nuxt 4 Comparison
Old Framework (Nuxt 3)
my-nuxt-app/
├── components/ # Vue components
├── layouts/ # Application layouts
├── pages/ # Pages/routes
├── plugins/ # Vue plugins
├── middleware/ # Route middleware
├── composables/ # Vue composables
├── utils/ # Utility functions
├── server/ # API and server handlers
├── public/ # Static assets
├── .nuxt/ # Generated files
├── app.vue # Root component
└── nuxt.config.ts # Configuration
New Framework (Nuxt 4)
my-nuxt-app/
├── app/ # 🆕 New main directory
│ ├── components/ # Vue components
│ ├── layouts/ # Application layouts
│ ├── pages/ # Pages/routes
│ ├── plugins/ # Vue plugins
│ ├── middleware/ # Route middleware
│ ├── composables/ # Vue composables
│ ├── utils/ # Utility functions
│ ├── assets/ # 🆕 Organized assets
│ │ ├── css/ # Styles
│ │ ├── images/ # Images
│ │ └── fonts/ # Fonts
│ └── app.vue # Root component
├── server/ # API and server handlers
├── shared/ # 🆕 Shared code
├── public/ # Static assets
├── .nuxt/ # Generated files
└── nuxt.config.ts # Configuration
🎯 Benefits of the New Structure
1. Best File Watching Performance
The new framework optimizes Chokidar’s file watching capabilities, providing a clear distinction between code that executes in the application.
// nuxt.config.ts - Optimized configuration
export default defineNuxtConfig({
// 🆕 Automatically enables the new structure
future: {
compatibilityVersion: 4
},
// 🆕 Better asset organization
css: [
'~/app/assets/css/main.css',
'~/app/assets/css/components.css'
],
// 🆕 More efficient auto-imports
imports: {
dirs: [
'app/composables',
'app/utils',
'shared/utils'
]
}
})
2. Clear Separation of Responsibilities
app/: Application-specific codeserver/: Server logic and APIsshared/: Code shared between client and serverpublic/: Public static assets
3. Best Organization for Large Projects
The structure facilitates organization in projects with multiple teams and complex functionalities.
🚀 Automatic Migration
Using the Upgrade Command
# 🆕 Automatic migration to Nuxt 4
npx nuxi@latest upgrade --force
# Check whether migration succeeded
npx nuxi@latest info
What the Command Does Automatically
- Moves directories to the new
app/structure - Updates settings on
nuxt.config.ts - Adjusts imports and path references
- Checks compatibility of dependencies
🔧 Manual Migration
Step by step
# 1. Create new structure
mkdir app
mkdir shared
# 2. Move main directories
mv components app/
mv layouts app/
mv pages app/
mv plugins app/
mv middleware app/
mv composables app/
mv utils app/
mv app.vue app/
# 3. Move assets (if they exist)
mkdir -p app/assets/css
mkdir -p app/assets/images
mkdir -p app/assets/fonts
# 4. Move style files
mv assets/css/* app/assets/css/ 2>/dev/null || true
mv assets/images/* app/assets/images/ 2>/dev/null || true
mv assets/fonts/* app/assets/fonts/ 2>/dev/null || true
# 5. Clean empty directories
rmdir assets 2>/dev/null || true
Update Imports
// ❌ Before (Nuxt 3)
import { useMyComposable } from '~/composables/useMyComposable'
import { formatDate } from '~/utils/date'
// ✅ After (Nuxt 4)
import { useMyComposable } from '~/app/composables/useMyComposable'
import { formatDate } from '~/app/utils/date'
// 🆕 Ou usar auto-imports (recomendado)
// Imports are automatic based on configuration
⚙️ Nuxt 4 Configuration
Basic Configuration
// nuxt.config.ts
export default defineNuxtConfig({
// 🆕 Ativa a nova estrutura
future: {
compatibilityVersion: 4
},
// 🆕 Directory configuration
dir: {
// Default directories (optional, already auto-configured)
pages: 'app/pages',
components: 'app/components',
layouts: 'app/layouts',
plugins: 'app/plugins',
middleware: 'app/middleware',
composables: 'app/composables',
utils: 'app/utils'
},
// 🆕 Optimized auto-imports
imports: {
dirs: [
'app/composables',
'app/utils',
'shared/utils'
]
},
// 🆕 CSS organizado
css: [
'~/app/assets/css/main.css',
'~/app/assets/css/tailwind.css'
]
})
Advanced Configuration
// nuxt.config.ts - Advanced configuration
export default defineNuxtConfig({
future: {
compatibilityVersion: 4
},
// 🆕 Better asset organization
vite: {
css: {
preprocessorOptions: {
scss: {
additionalData: '@import "~/app/assets/scss/variables.scss";'
}
}
}
},
// 🆕 Auto-imports com aliases
imports: {
dirs: [
'app/composables',
'app/utils',
'shared/utils'
],
global: true
},
// 🆕 Optimized build configuration
build: {
transpile: ['vue-toastification']
}
})
💡 Practical Examples
Example of Optimized Organization
// app/components/ui/Button.vue
<template>
<button
:class="buttonClasses"
@click="handleClick"
>
<slot />
</button>
</template>
<script setup lang="ts">
// 🆕 Auto-import de utils do app/
const { generateButtonClass } = useButtonUtils()
// 🆕 Auto-import de composables
const { trackButtonClick } = useAnalytics()
interface Props {
variant: 'primary' | 'secondary' | 'danger'
size: 'sm' | 'md' | 'lg'
disabled?: boolean
}
const props = withDefaults(defineProps<Props>(), {
variant: 'primary',
size: 'md',
disabled: false
})
const buttonClasses = computed(() =>
generateButtonClass(props.variant, props.size, props.disabled)
)
const handleClick = () => {
if (!props.disabled) {
trackButtonClick(props.variant)
}
}
</script>
Project Structure Example
// Recommended structure for large projects
my-nuxt-app/
├── app/
│ ├── components/
│ │ ├── ui/ # Base components (Button, Input, etc.)
│ │ ├── forms/ # Form components
│ │ └── layout/ # Layout components
│ ├── composables/
│ │ ├── useAuth.ts # Authentication
│ │ ├── useApi.ts # API calls
│ │ └── useCache.ts # Cache management
│ ├── utils/
│ │ ├── date.ts # Date utilities
│ │ ├── validation.ts # Validations
│ │ └── formatting.ts # Formatting
│ └── assets/
│ ├── css/
│ │ ├── main.css
│ │ ├── variables.css
│ │ └── components.css
│ └── images/
├── shared/
│ ├── types/ # Shared types
│ ├── constants/ # Constantes
│ └── utils/ # Shared utilities
└── server/
├── api/ # API routes
├── middleware/ # Server middleware
└── plugins/ # Server plugins
🚨 Common Problems and Solutions
1. Broken Imports
// ❌ Common error after migration
import { something } from '~/components/Something'
// ✅ Solution
import { something } from '~/app/components/Something'
// 🆕 Ou melhor ainda, usar auto-imports
// The component will be imported automatically
2. Assets Not Found
// ❌ Caminho antigo
background-image: url('~/assets/images/hero.jpg')
// ✅ New path
background-image: url('~/app/assets/images/hero.jpg')
3. Build Settings
// ❌ Old configuration
css: ['~/assets/css/main.css']
// ✅ New configuration
css: ['~/app/assets/css/main.css']
🔍 Migration Check
Verification Checklist
- All directories moved to
app/ - Imports have been updated
- Assets are on the correct paths
-
nuxt.config.tshas been updated - Application starts without errors
- Build works correctly
- Auto-imports work
Verification Commands
# Verify structure
tree app/ -I node_modules
# Verify build
npm run build
# Verify dev
npm run dev
# Verify types
npm run typecheck
🎯 Next Steps
After migrating the directory structure, you can:
- Explore the new caching system - Read the article about Data Fetching and Cache
- Learn about Type Safety - Read the article about TypeScript
- Optimize performance - Read the article about Performance
✨ Conclusion
Nuxt 4’s new directory structure represents a significant evolution in project organization. Although the migration may seem complex initially, the benefits in terms of performance, organization and scalability make it worth the effort.
The app/ framework isn’t just a cosmetic change - it’s an architectural overhaul that prepares your projects for the future of web development.
🔗 Official Resources: