Nuxt automatically imports Vue APIs, Nuxt composables, your own composables, utilities, and components. You never write import { ref } from 'vue' or import { useFetch } from '#app' in a Nuxt project. Everything is available directly.
What gets auto-imported
Vue APIs (ref, computed, watch, lifecycle hooks, etc.):
<script setup>
const count = ref(0)
const doubled = computed(() => count.value * 2)
watch(count, (val) => console.log(val))
onMounted(() => console.log('ready'))
</script>Nuxt composables (useFetch, useRoute, useState, useHead, etc.):
<script setup>
const route = useRoute()
const config = useRuntimeConfig()
const { data } = await useFetch('/api/posts')
useHead({ title: 'My Page' })
useSeoMeta({ description: 'Page description' })
</script>Your composables from composables/:
// composables/useAuth.ts
export function useAuth() {
const user = useState<User | null>('user', () => null)
const isLoggedIn = computed(() => !!user.value)
return { user, isLoggedIn }
}<script setup>
const { user, isLoggedIn } = useAuth() // no import needed
</script>Your utilities from utils/:
// utils/format.ts
export function formatDate(date: Date) {
return date.toLocaleDateString()
}<script setup>
const date = formatDate(new Date()) // no import needed
</script>Components from components/:
<template>
<!-- no import needed -->
<AppHeader />
<BaseButton>Click</BaseButton>
</template>How components are named
Directory structure maps to component names:
components/
├── AppHeader.vue → <AppHeader />
├── base/
│ └── Button.vue → <BaseButton />
└── form/
├── Input.vue → <FormInput />
└── Select.vue → <FormSelect />The folder path becomes the prefix. You can disable this with pathPrefix: false in the config.
Lazy loading components
Prefix any component with Lazy and it becomes code-split into its own chunk, loaded only when rendered:
<template>
<LazyHeavyChart v-if="showChart" />
<button @click="showChart = true">Show chart</button>
</template>You don't create a separate "Lazy" version. Nuxt generates the lazy variant automatically for every component.
File scanning rules
Only top-level files in composables/ and utils/ are scanned:
composables/
├── useAuth.ts → auto-imported
├── useCounter.ts → auto-imported
└── helpers/
└── validate.ts → NOT auto-importedTo include nested files, either re-export from an index.ts or configure scanning:
// nuxt.config.ts
export default defineNuxtConfig({
imports: {
dirs: ['composables', 'composables/**']
}
})Server auto-imports
server/utils/ works the same way for server routes:
// server/utils/db.ts
export function getDb() {
return createPool(process.env.DATABASE_URL)
}
// server/api/users.get.ts — no import needed
export default defineEventHandler(() => {
const db = getDb()
return db.query('SELECT * FROM users')
})Auto-importing third-party libraries
// nuxt.config.ts
export default defineNuxtConfig({
imports: {
presets: [
{
from: '@vueuse/core',
imports: ['useMouse', 'useWindowSize']
},
{
from: 'date-fns',
imports: ['format', 'parseISO']
}
]
}
})Explicit imports with #imports
When you need to be explicit (tests, external files, clarity), import from #imports:
import { ref, useFetch, useRoute } from '#imports'Disabling auto-imports
export default defineNuxtConfig({
imports: {
autoImport: false // disable all auto-imports
}
})After disabling, you must import everything manually, including Vue APIs.