N
Nuxtβ€’2mo ago
Meldiron

Static files with Nuxt (Nitro) handler preset

When self-hosting Nuxt build, by default it uses node-server preset. This gives an entrypoint that runs on a port and serves website. All works well in this setup. I wanted to add more logic around this, such as authorization headers, error handling, metrics tracking, and more. So I switch to node-listener preset, but static files stops working, like robots.txt in public directory. I went the simple route and simply added static serving on my own, from public directory. This worked well, until I faced problem with nitro configuration in nuxt.config.ts, for example this one:
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
compatibilityDate: '2025-07-15',
devtools: { enabled: true },
nitro: {
routeRules: {
"/img/**": { headers: { "cache-control": "public,max-age=6666,s-maxage=6666" } },
"/_nuxt/**": { headers: { "cache-control": "public,max-age=6666,s-maxage=6666" } },
}
},
})
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
compatibilityDate: '2025-07-15',
devtools: { enabled: true },
nitro: {
routeRules: {
"/img/**": { headers: { "cache-control": "public,max-age=6666,s-maxage=6666" } },
"/_nuxt/**": { headers: { "cache-control": "public,max-age=6666,s-maxage=6666" } },
}
},
})
Notice I have images, and I want then cached for 6666 seconds. When I build this as node-server, my img/sample-3.png has correct cache control headers. When I build for node-listener, they dont get served (shows index HTML instead). When I add my own static serving, it doesnt respect nitro routeRules, so headers dont get added. --- What is recommended solution for this problem? A) Is there a way to tell node-listener to also serve static files? B) When serving static files on my own, are there any helpers to use to respect those nitro configurations?
6 Replies
kapa.ai
kapa.aiβ€’2mo ago
Hi @Meldiron. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- I'm sorry, but the knowledge sources do not explicitly document the behavior of the Nitro node-listener preset regarding static file serving, nor do they provide a direct solution for making node-listener serve static files from the public directory or for applying routeRules to custom static file serving. Here's what is clear from the documentation: - The default node-server preset automatically serves static files from the public directory and applies routeRules (such as custom headers) to those files, as you observed. - When you switch to node-listener and implement your own static file serving, Nitro's built-in routeRules (like custom cache headers) are not applied, since your custom server logic bypasses Nitro's internal handling. Regarding your specific questions: A) Is there a way to tell node-listener to also serve static files?
The knowledge sources do not mention a configuration or helper to make node-listener automatically serve static files from the public directory as node-server does. There is no documented flag or option to enable this behavior in the provided sources. B) When serving static files on my own, are there any helpers to use to respect those nitro configurations?
The documentation does not mention any official helper or utility to extract or apply Nitro's routeRules (such as cache headers) to your own static file server logic. The routeRules feature is described as being handled internally by Nitro's server engine, and there is no API documented for external use in custom listeners or middleware to access or apply these rules manually. Summary:
- If you need Nitro's static file serving and routeRules support, the recommended approach is to use the node-server preset. - If you must use node-listener and custom static file serving, you will need to manually implement logic to match Nitro's routeRules behavior, as there is no documented helper or API for this in the knowledge sources. If you need more advanced customization (like custom middleware, metrics, etc.) but want to retain Nitro's static file and header handling, consider extending Nitro via its plugin or middleware system rather than replacing its static file serving entirely. However, the exact approach for this is not detailed in the provided documentation. If you need further guidance, you may want to consult the Nitro documentation or raise an issue with the Nuxt team for more advanced use cases. Hybrid Rendering and Route Rules
Nuxt Deployment Presets ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.aiβ€’2mo ago
<@287294735054274560> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Meldiron
MeldironOPβ€’2mo ago
Not sure how helpful, but I noticed .output/server/chunks/nitro/nitro.mjs has _inlineRuntimeConfig, which has those cache configuration (routeRules), and it also has "public": {}. Maybe if this public wasnt empty, it would work okay? Should it be empty? πŸ€”
https://nitro.build/guide/assets#production-public-assets
Additionally, I found out that
When building your Nitro app, the server/public/ directory will be copied to .output/public/ and a manifest with metadata will be created and embedded in the server bundle.
I have those files in .output/public, but my metadata is empty object πŸ€” After more comparing, I noticed node-server generated const assets twice, one has actual files from public direcotry. but doing it with node-listener doesnt generate that. This seems either intentional, or a bug. Not sure what next steps would be best, Ill just wait for answer πŸ™Œ tldr: node-listener build preset from Nitro doesnt seem to handle static files. And when handling on my own, I can't respect routeRules, because those are Nitro configuration
Tessa
Tessaβ€’2mo ago
Bumping for human eyes πŸ™‚ this is blocking our Appwrite Sites Nuxt SSR rollout (affects lots of developers on Sites). could someone please review @Meldiron findings and advise whether this is expected vs. a bug? thanks!
Chirag Aggarwal
Chirag Aggarwalβ€’2mo ago
Bumping this too!
Meldiron
MeldironOPβ€’2mo ago
Bumping again ☝️ I explored using standalone server instead if middleware (handler) approach, and made it work, but due to existing builds on our platform, we would be introducing breaking change. It would be much simpler solution if we found a way to respect routeRules in middleware approach πŸ™

Did you find this page helpful?