Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For images used by Vue components, keep files in the source tree and reference them in a Vue template or import them in JavaScript. Vite then includes those assets in the build and emits URLs for production. Put an image in the project-root public/ directory instead when it needs a fixed filename or must be copied as-is.

Use a source asset for images that belong to a Vue component

With the Vue plugin enabled, image references in a Vue single-file component template are converted into imports. Vite can then track the image as part of the build graph and emit it as a production asset, typically with a hashed filename. This also lets applicable plugins process the asset. See the Vite static asset handling guide.

Reference the image directly in the template

For an image at src/assets/hero.png and a component at src/components/Hero.vue:

<template>
  <img src="../assets/hero.png" alt="A scenic landscape">
</template>

The path is relative to the component file, so adjust it to match your project structure. The Vue plugin makes this template reference part of Vite’s asset graph.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Import the image and bind its URL

Importing is useful when you need to choose or pass the image URL in component logic:

<script setup>
import heroUrl from '../assets/hero.png'
</script>

<template>
  <img :src="heroUrl" alt="A scenic landscape">
</template>

A static asset import resolves to a URL. CSS url() references receive similar build handling. Vite recognizes common image, media, and font types; use ?url to explicitly request URL handling for other file types.

Choose between src and public

Need Use Result
The image is used by a component and should participate in the build A Vue template reference or JavaScript import from the source tree Vite tracks the reference and emits a production asset URL, commonly with a hashed filename.
The filename must remain fixed, or the file must be copied unchanged A file in the project-root public/ directory Vite serves it from the site root during development and copies it unchanged to the output root.
A runtime URL must account for a configured deployment base import.meta.env.BASE_URL Vite statically replaces this exact expression with the configured base.
A dynamic choice comes from a finite, known set of files A statically analyzable new URL() pattern Vite can transform supported patterns by enumerating matching files.
A path is arbitrary runtime data or code runs in SSR A deployment-appropriate runtime URL strategy Vite cannot bundle an un-analyzable path; the documented new URL() pattern also has SSR limitations.

Vite’s guidance is to “prefer importing assets unless you specifically need the guarantees provided by the public directory.” See the static asset guide and shared options.

Reference public files from the site root

For public/logo.png, use a root-absolute URL such as /logo.png:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
<img src="/logo.png" alt="Company logo">

Do not put /public/ in the URL. The directory name is stripped: the public file is served at /logo.png, not /public/logo.png.

Handle dynamic image URLs carefully

Known static path

When JavaScript needs a URL for a statically named file, use a path Vite can analyze:

const imageUrl = new URL('./img.png', import.meta.url).href

Adapt the relative path to the JavaScript file containing this expression.

Finite set of images

For a finite set in a known directory, the Vite guide documents a template-literal new URL() pattern that can be transformed by enumerating matching files. The important constraint is that the pattern must be statically analyzable. A path assembled from arbitrary runtime input is not automatically discovered and bundled; Vite leaves such an expression unchanged. Do not rely on this pattern for SSR, where the guide documents limitations.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Make asset URLs work under a deployment subpath

If the application is hosted below a path such as /app/ rather than the domain root, configure Vite’s base for that deployment. Vite adjusts JavaScript-imported asset URLs, CSS url() references, and HTML asset references during the build. The exact deployment path matters; test the output at the URL where it will actually be served. See Building for Production.

When the final base path is unknown, Vite also supports a relative base, written as ./ or an empty string. The documentation notes a browser-support caveat involving import.meta; check that limitation against the browsers your application supports.

For a URL assembled at runtime, use the exact expression import.meta.env.BASE_URL, which Vite statically replaces with the configured base. Avoid assuming that a string such as '/images/' + filename will be rewritten or that a public file reference automatically gains a deployment prefix.

Build and verify the production assets

  1. Confirm Vue plugin setup. Check that the Vue Vite plugin is enabled if you expect asset references in Vue single-file component templates to be processed.
  2. Check the source path. Resolve the image path from the component or script file that references it. For a public file, use its root URL and omit /public/.
  3. Set the deployment base. Configure Vite’s base to match the production subpath, if the app is not served from the domain root.
  4. Run the production build. Run vite build using the project’s configured package scripts or local Vite executable. Vite treats index.html as source code and part of the module graph, and processes its asset references during build. See Getting Started and Building for Production.
  5. Serve the output at its real base path. Check that component images, CSS images, and HTML references load from the built site at the intended production URL, especially for deployments such as GitHub Pages that use a subpath.

Assets smaller than the configured assetsInlineLimit may be inlined as data URLs. The threshold depends on the installed Vite version and project configuration, so check those rather than relying on a universal size figure.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshoot missing or incorrect images

  • Image works in development but is missing after deployment: Check whether the site is hosted under a subpath and whether the Vite base setting matches it. Inspect the generated asset URL and test the build from the actual deployment path.
  • Browser requests /public/... and gets a missing-file error: Remove /public from the URL. A file at public/images/pic.png is served as /images/pic.png.
  • Template image path is unresolved: Check the path relative to the Vue component and confirm the Vue plugin is enabled. For clearer logic or a value used elsewhere, import the file in the script and bind the returned URL.
  • Runtime-selected image disappears in the build: Vite may not be able to analyze the computed path. Use a statically analyzable pattern for a known finite set, import known files explicitly, or choose a runtime URL strategy appropriate to the deployment.
  • Image URL fails only in SSR: Do not assume new URL('./img.png', import.meta.url) will work as it does in a browser build. The Vite asset guide documents SSR limitations for this pattern; use an SSR-compatible URL strategy.
  • Asset appears as a data URL instead of a separate file: Check the installed Vite version and assetsInlineLimit configuration. Inlining is configuration-dependent.

Or skip the browser setup

If you need screenshots of pages that show your bundled images, ScreenshotNeo provides a website screenshot API and MCP server. For a screenshot, make one GET request:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp

See the ScreenshotNeo documentation for request options. Cookie banners are accepted and removed before capture, along with known newsletter popups and chat widgets; those steps can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and the response identifies the page verdict and billing status in headers. Its MCP server lets AI agents use screenshot tools. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots. Learn about ScreenshotNeo or sign up free for 1,000 screenshots a month with no card.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.