Images, fonts, SVGs, media, WebAssembly, PDFs, and text files are handled automatically when referenced from JavaScript.
Volt follows Vite-style asset import semantics in both dev and production:
- JavaScript imports become modules that export a string.
new URL("./asset.ext", import.meta.url)participates in the production graph.- Production builds copy referenced files with content-hashed names and rewrite JavaScript URLs to
/assets/....
CSS is parsed and bundled by LightningCSS through Vize. Production builds also parse CSS with Vize's LightningCSS-backed AST API and rewrite relative url(...) asset references to content-hashed /assets/... URLs. In dev, CSS imports are rewritten to dev-server asset URLs so injected styles resolve from the source tree.
Default imports
Small files under the inline limit are inlined as base64 data URIs:
import icon from './icon.svg'
// icon = "data:image/svg+xml;base64,..."Larger files are copied to the output directory and exported as public URLs:
import photo from './photo.jpg'
// photo = "/assets/photo-a1b2c3d4.jpg"The default inline limit is 4 KB.
Query modes
Use query suffixes when you need a specific representation:
import source from './message.txt?raw'
import url from './logo.svg?url'
import inlineIcon from './icon.svg?inline'
import fileUrl from './small-icon.svg?no-inline'| Query | Result |
|---|---|
?raw | exports file contents as a string |
?url | exports a public URL |
?inline | exports a data URI even when the file is larger than the inline limit |
?no-inline | exports a public URL even when the file is small |
new URL(..., import.meta.url)
Relative asset URL constructors are rewritten during production builds:
const logo = new URL('./logo.svg', import.meta.url).hrefThe referenced file is copied with a content hash and the bundled JavaScript points at the emitted /assets/... URL.
Only relative specifiers that resolve to known asset extensions are rewritten. Remote URLs, absolute URLs, and non-asset modules are left unchanged.
CSS URLs
Production builds rewrite relative CSS asset URLs through the same hashed asset pipeline as JavaScript references:
.logo {
background-image: url('./images/logo.svg');
}The referenced file is copied to the output directory and the final CSS points at /assets/logo-a1b2c3d4.svg. The emitted asset filename is also included in the CSS manifest entry's assets list. This is parser-backed: Volt parses CSS with Vize's LightningCSS AST API and rewrites URL nodes, including nested usages such as image-set(url(...)).
Root-absolute URLs (/images/logo.svg), external URLs, data URLs, missing files, and unknown extensions are left unchanged. Use those forms for assets that should stay at Phoenix/static or public-directory paths.
Phoenix static files and optional public directory
In Phoenix apps, stable root files usually belong in priv/static and are served by Phoenix through Plug.Static:
priv/static/favicon.svg -> /favicon.svg
priv/static/robots.txt -> /robots.txtVolt's asset pipeline is for files referenced by JavaScript when you want dependency tracking, hashing, and URL rewriting.
For Vite migration compatibility, Volt also supports an optional public_dir. It is disabled by default. When enabled, files in that directory are served and copied without transformation:
config :volt,
public_dir: "public"public/favicon.svg -> /favicon.svgPublic directory files are not hashed and are not processed by import query modes. Prefer module imports for assets referenced by JavaScript when you want hashing and dependency tracking.
Supported formats
Images (.svg, .png, .jpg, .jpeg, .gif, .webp, .avif, .ico), fonts (.woff, .woff2, .ttf, .otf, .eot), media (.mp4, .webm, .ogg, .mp3, .wav), and other formats (.pdf, .wasm, .txt).