Assets
Nitro supports two types of assets: public assets served directly to clients and server assets bundled into the server for programmatic access.
Public Assets
Nitro handles assets via the public/ directory.
All assets in public/ directory will be automatically served. This means that you can access them directly from the browser without any special configuration.
public/
image.png <-- /image.png
video.mp4 <-- /video.mp4
robots.txt <-- /robots.txt
Caching and Headers
Public assets are served with automatic ETag and Last-Modified headers for conditional requests. When the client sends If-None-Match or If-Modified-Since headers, Nitro returns a 304 Not Modified response.
For assets served from a non-root baseURL (such as /build/), Nitro prevents fallthrough to application handlers. If a request matches a public asset base but the file is not found, a 404 is returned immediately.
Production Public Assets
When building your Nitro app, the public/ directory will be copied to .output/public/ and a manifest with metadata will be created and embedded in the server bundle.
{
"/image.png": {
"type": "image/png",
"etag": "\"4a0c-6utWq0Kbk5OqDmksYCa9XV8irnM\"",
"mtime": "2023-03-04T21:39:45.086Z",
"size": 18956
},
"/robots.txt": {
"type": "text/plain; charset=utf-8",
"etag": "\"8-hMqyDrA8fJ0R904zgEPs3L55Jls\"",
"mtime": "2023-03-04T21:39:45.086Z",
"size": 8
},
"/video.mp4": {
"type": "video/mp4",
"etag": "\"9b943-4UwfQXKUjPCesGPr6J5j7GzNYGU\"",
"mtime": "2023-03-04T21:39:45.085Z",
"size": 637251
}
}
This allows Nitro to know the public assets without scanning the directory, giving high performance with caching headers.
Custom Public Asset Directories
You can configure additional public asset directories using the publicAssets config option. Each entry supports the following properties:
dir-- Path to the directory (resolved relative torootDir).baseURL-- URL prefix for serving assets (default:"/").maxAge-- Cachemax-agein seconds. When set, aCache-Control: public, max-age=<value>, immutableheader is applied via route rules.fallthrough-- Whether requests should fall through to application handlers when the asset is not found. Top-level (baseURL: "/") directories default totrue; non-root directories default tofalse.ignore-- Passfalseto disable ignore patterns, or an array of glob patterns to override the globalignoreoption.
import { defineNitroConfig } from "nitro/config";
export default defineNitroConfig({
publicAssets: [
{
baseURL: "build",
dir: "public/build",
maxAge: 3600,
},
],
});
In this example, files in public/build/ are served under /build/ with a one-hour cache and no fallthrough to application handlers.
Compressed Public Assets
Nitro can generate pre-compressed versions of your public assets during the build. When a client sends an Accept-Encoding header, the server will serve the compressed version if available. Supported encodings are gzip (.gz), brotli (.br), and zstd (.zst).
Set compressPublicAssets: true to enable all encodings:
import { defineNitroConfig } from "nitro/config";
export default defineNitroConfig({
compressPublicAssets: true,
});
Or pick specific encodings:
import { defineNitroConfig } from "nitro/config";
export default defineNitroConfig({
compressPublicAssets: {
gzip: true,
brotli: true,
zstd: false,
},
});
.map) are excluded.Server Assets
All assets in assets/ directory will be added to the server bundle. After building your application, you can find them in the .output/server/chunks/raw/ directory. Be careful with the size of your assets, as they will be bundled with the server bundle.
useStorage(), assets won't be included in the server bundle.They can be addressed by the assets:server mount point using the storage layer.
For example, you could store a json file in assets/data.json and retrieve it in your handler:
import { defineHandler } from "nitro";
export default defineHandler(async () => {
const data = await useStorage("assets:server").get("data.json");
return data;
});
Custom Server Assets
In order to add assets from a custom directory, you will need to define a path in your nitro config. This allows you to add assets from a directory outside of the assets/ directory.
Each entry in serverAssets supports the following properties:
baseName-- Name used as the storage mount point (accessed viaassets:<baseName>).dir-- Path to the directory (resolved relative torootDir).pattern-- Glob pattern for file inclusion (default:"**/*").ignore-- Array of glob patterns to exclude files.
import { defineNitroConfig } from "nitro/config";
export default defineNitroConfig({
serverAssets: [
{
baseName: "templates",
dir: "./templates",
},
],
});
Then you can use the assets:templates base to retrieve your assets.
import { defineHandler } from "nitro";
export default defineHandler(async (event) => {
const html = await useStorage("assets:templates").get("success.html");
return html;
});
fs unstorage driver. In production, they are bundled into the server as lazy imports with pre-computed metadata (MIME type, ETag, modification time).