Gabriel Caiana

Nuxt 4: New Directory Structure and Migration Guide


Table of contents
  1. 🧭 Quick Navigation Guide
  2. 🔄 Nuxt 3 vs Nuxt 4 Comparison
  3. Old Framework (Nuxt 3)
  4. New Framework (Nuxt 4)
  5. 🎯 Benefits of the New Structure
  6. 1. Best File Watching Performance
  7. 2. Clear Separation of Responsibilities
  8. 3. Best Organization for Large Projects
  9. 🚀 Automatic Migration
  10. Using the Upgrade Command
  11. What the Command Does Automatically
  12. 🔧 Manual Migration
  13. Step by step
  14. Update Imports
  15. ⚙️ Nuxt 4 Configuration
  16. Basic Configuration
  17. Advanced Configuration
  18. 💡 Practical Examples
  19. Example of Optimized Organization
  20. Project Structure Example
  21. 🚨 Common Problems and Solutions
  22. 1. Broken Imports
  23. 2. Assets Not Found
  24. 3. Build Settings
  25. 🔍 Migration Check
  26. Verification Checklist
  27. Verification Commands
  28. 🎯 Next Steps
  29. ✨ 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

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 code
  • server/: Server logic and APIs
  • shared/: Code shared between client and server
  • public/: 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

  1. Moves directories to the new app/ structure
  2. Updates settings on nuxt.config.ts
  3. Adjusts imports and path references
  4. 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.ts has 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:

  1. Explore the new caching system - Read the article about Data Fetching and Cache
  2. Learn about Type Safety - Read the article about TypeScript
  3. 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: