shared

Use the shared/ directory to share functionality between the Vue app and the Nitro server.

The shared/ directory allows you to share code that can be used in both the Vue app and the Nitro server.

The shared/ directory is available in Nuxt v3.14+.
Code in the shared/ directory cannot import any Vue or Nitro code.

Why You Cannot Mix Vue and Nitro Code

Nuxt builds two separate bundles: the Vue app (client and server-side rendering) and the Nitro server (API routes, server middleware, server plugins). They are bundled independently and run in different contexts. Code in the shared/ directory is used in both bundles, so it cannot import from either.

Vue App Code in Nitro

Components and composables need the Vue app runtime and often the Nuxt context (for example useNuxtApp() or useRoute()), neither of which exists in Nitro. Importing them into server code can cause build or runtime errors, and can pull the Vue app's dependencies into your server bundle.

Nitro Code in the Vue App

Server-only code (such as Node APIs, Nitro utilities, or server route handlers) must not run in the browser. Importing it into your app can break the client build, cause runtime errors in the browser, or leak server logic into the client bundle.

Type-Only Imports

import type is erased at compile time and does not pull runtime code into the other bundle, so importing only types across the boundary may appear to work. Even so, keep shared types (such as API response types) in shared/types/, where they are auto-imported in both contexts. This keeps the boundary clear, avoids accidentally turning a type import into a value import later, and matches Nuxt's separate type contexts for app, server, and shared code.

Usage

Method 1: Named export

shared/utils/capitalize.ts
export const capitalize = (input: string) => {
  return input[0] ? input[0].toUpperCase() + input.slice(1) : ''
}

Method 2: Default export

shared/utils/capitalize.ts
export default function (input: string) {
  return input[0] ? input[0].toUpperCase() + input.slice(1) : ''
}

You can now use auto-imported utilities in your Nuxt app and server/ directory.

app/app.vue
<script setup lang="ts">
const hello = capitalize('hello')
</script>

<template>
  <div>
    {{ hello }}
  </div>
</template>
server/api/hello.get.ts
export default defineEventHandler((event) => {
  return {
    hello: capitalize('hello'),
  }
})

How Files Are Scanned

Only files in the shared/utils/ and shared/types/ directories will be auto-imported. Files nested within subdirectories of these directories will not be auto-imported unless you add these directories to imports.dirs and nitro.imports.dirs.

The way shared/utils and shared/types auto-imports work and are scanned is identical to the app/composables/ and app/utils/ directories.
Read more in Docs > 4 X > Directory Structure > App > Composables#how Files Are Scanned.
Directory Structure
-| shared/
---| capitalize.ts        # Not auto-imported
---| formatters
-----| lower.ts           # Not auto-imported
---| utils/
-----| lower.ts           # Auto-imported
-----| formatters
-------| upper.ts         # Not auto-imported
---| types/
-----| bar.ts             # Auto-imported

Any other files you create in the shared/ folder must be manually imported using the #shared alias (automatically configured by Nuxt):

Importing From #shared
// For files directly in the shared directory
import capitalize from '#shared/capitalize'

// For files in nested directories
import lower from '#shared/formatters/lower'

// For files nested in a folder within utils
import upper from '#shared/utils/formatters/upper'

This alias ensures consistent imports across your application, regardless of the importing file's location.

Read more in Docs > 4 X > Guide > Concepts > Auto Imports.