Fix: Directly Configuring vite.publicDir Not Supported in Nuxt

Error message:
Directly configuring `vite.publicDir` is not supported. Use `dir.public` instead.
initialization 2025-01-25

What Causes This Error?

This error occurs when you try to configure Vite’s publicDir option directly in the Nuxt config. Nuxt manages this setting and provides its own way to configure it.

The Problem

// nuxt.config.ts
export default defineNuxtConfig({
  vite: {
    // ❌ Wrong - can't configure publicDir directly
    publicDir: './assets/public'
  }
})

The Fix

Use dir.public

// nuxt.config.ts
export default defineNuxtConfig({
  // ✅ Correct - use Nuxt's dir option
  dir: {
    public: 'public'  // Default value
  }
})

Custom Public Directory

Change Location

// nuxt.config.ts
export default defineNuxtConfig({
  dir: {
    public: 'static'  // Use 'static' instead of 'public'
  }
})

Then structure:

my-nuxt-app/
├── static/              ← Custom public directory
│   ├── favicon.ico
│   ├── robots.txt
│   └── images/
├── nuxt.config.ts
└── ...

Multiple Locations (Not Directly Supported)

If you need files from multiple locations:

// nuxt.config.ts
export default defineNuxtConfig({
  nitro: {
    publicAssets: [
      {
        dir: 'public',
        baseURL: '/'
      },
      {
        dir: 'assets/static',
        baseURL: '/static'
      }
    ]
  }
})

All dir Options

// nuxt.config.ts
export default defineNuxtConfig({
  dir: {
    // All available directory options
    assets: 'assets',       // CSS, images for build
    layouts: 'layouts',     // Layout components
    middleware: 'middleware',
    modules: 'modules',
    pages: 'pages',
    plugins: 'plugins',
    public: 'public',       // Static files (served as-is)
    static: 'public'        // Alias for public (Nuxt 2 compat)
  }
})

Understanding public vs assets

public/ Directory

  • Files served as-is at root URL
  • Not processed by bundler
  • Use for: robots.txt, favicon.ico, sitemap.xml
  • Access: /robots.txtpublic/robots.txt
public/
├── robots.txt          → /robots.txt
├── favicon.ico         → /favicon.ico
└── images/
    └── logo.png        → /images/logo.png

assets/ Directory

  • Processed by Vite/bundler
  • Fingerprinted for caching
  • Use for: Images, CSS, fonts referenced in code
  • Import in code: import logo from '~/assets/logo.png'
assets/
├── css/
│   └── main.css        → import '~/assets/css/main.css'
└── images/
    └── logo.png        → import logo from '~/assets/images/logo.png'

Nitro Static Assets

For production deployment:

// nuxt.config.ts
export default defineNuxtConfig({
  nitro: {
    publicAssets: [
      {
        dir: 'public',
        maxAge: 60 * 60 * 24 * 365  // 1 year cache
      }
    ]
  }
})

Common Directory Structures

Default

my-nuxt-app/
├── public/          ← Static files
├── assets/          ← Processed assets
├── pages/
├── components/
└── nuxt.config.ts

Custom (src Directory)

// nuxt.config.ts
export default defineNuxtConfig({
  srcDir: 'src',
  dir: {
    public: '../public'  // Relative to srcDir
  }
})
my-nuxt-app/
├── public/          ← Static files (outside src)
├── src/
│   ├── pages/
│   ├── components/
│   └── assets/
└── nuxt.config.ts

Migration from Nuxt 2

// Nuxt 2
export default {
  dir: {
    static: 'static'  // Called 'static' in Nuxt 2
  }
}

// Nuxt 3
export default defineNuxtConfig({
  dir: {
    public: 'static'  // Now called 'public', but can use 'static' folder
  }
})

Quick Checklist

  • Use dir.public instead of vite.publicDir
  • Public files go in public/ directory
  • Processed assets go in assets/ directory
  • Use nitro.publicAssets for advanced configuration
  • Path is relative to project root (or srcDir)