Repository navigation
Build fails with compatibilityVersion: 4 and TypeScript templates added via addTemplate #28995
Description
Environment
Nuxt project info: 09:23:49
------------------------------
- Operating System: Linux
- Node Version: v20.17.0
- Nuxt Version: 3.13.1
- CLI Version: 3.13.1
- Nitro Version: 2.9.7
- Package Manager: npm@10.7.0
- Builder: -
- User Config: -
- Runtime Modules: -
- Build Modules: -
------------------------------
Reproduction
This example repo shows the issue: https://github.com/dulnan/nuxt4-server-options-reproduction
npm run devworksnpm run dev:builddoes not work
Describe the bug
Setting compatibilityVersion: 4 breaks almost all modules of mine (issues were created for dulnan/nuxt-multi-cache#74 and dulnan/nuxt-graphql-middleware#37, but 4 other modules are affected too). What they all have in common is a way for module users to provide runtime configuration in the form of functions. As there is no built-in way to easily do that, I stitch this together using templates. This has always been a bit of a pain, but for the last 1.5 years or so it has worked fairly okay.
Now with Nuxt 4 and the new compatibilityVersion option, this approach does not seem to work anymore. I have created a basic reproduction here: https://github.com/dulnan/nuxt4-server-options-reproduction
In essence:
- Users can provide runtime "server options" by creating a file in
~/server/myModule.serverOptions.ts - Using
addTemplatethe module creates a "compiled"example.serverOptions.tsfile that imports the user-provided file and exports functions with default implementations - A server handler provided by the module imports the compiled template and calls a method on it
This works when running npm run dev, however npm run dev:build fails with the following error:
[plugin inject] playground/node_modules/.cache/nuxt/.nuxt/example.serverOptions.ts: rollup-plugin-inject: failed to parse /run/media/dulnan/Storage/development/nuxt4-server-options/playground/node_modules/.cache/nuxt/.nuxt/example.serverOptions.ts. Consider restricting the plugin to particular files via options.include
ERROR RollupError: playground/node_modules/.cache/nuxt/.nuxt/example.serverOptions.ts (6:12): Expected ',', got '{' (Note that you need plugins to import files that are not JavaScript) nitro 09:22:21
4:
5: // Import type from the module.
6: import type { ExampleModuleFunctionType } from '../../../../../src/types'
^
7:
8: export const foobar: ExampleModuleFunctionType = () => {
ERROR playground/node_modules/.cache/nuxt/.nuxt/example.serverOptions.ts (6:12): Expected ',', got '{' (Note that you need plugins to import files that are not JavaScript) 09:22:21
at getRollupError (node_modules/rollup/dist/es/shared/parseAst.js:392:41)
at ParseError.initialise (node_modules/rollup/dist/es/shared/node-entry.js:11495:28)
at convertNode (node_modules/rollup/dist/es/shared/node-entry.js:13193:10)
at convertProgram (node_modules/rollup/dist/es/shared/node-entry.js:12537:12)
at Module.setSource (node_modules/rollup/dist/es/shared/node-entry.js:14356:24)
at async ModuleLoader.addModuleSource (node_modules/rollup/dist/es/shared/node-entry.js:19047:13)
The exact same code works when removing compatibilityVersion: 4 and the playground builds just fine.
So I'm not sure if this is actually a bug or if what I'm doing is (and has been) wrong anyway. I'm very much open to adapting a different approach. However, not being able to use TypeScript templates kind of sounds like a bug, so I decided to file this issue.
Additional context
No response
Logs
No response
Activity
github-actions commentedon Sep 14, 2024
Stackblitz link for the reproduction: Stackblitz
vernaillen commentedon Sep 14, 2024
This error started appearing after upgrading to Nuxt 3.13.1, in which this new build cache feature was introduced: #28726
When not in compatibilityVersion 4, the buildCache is disabled by default, and then the error does not occur.
The error appears when enabling the buildCache or when enabling compatibilityVersion 4.
I also noticed that the error does not occur when there is no build cache yet from a previous build.
To be able to build and deploy on vercel I'm using this build command as a workaround:
danielroe commentedon Sep 14, 2024
Your code is assuming a relative path from the Nuxt build directory:
There are a couple of problems with this:
nuxt.options.serverDirbuildDiris not at the top level, next toserver/, this will not work (this is configurable innuxt.options.buildDir)The reason this happens after turning on
compatibilityVersion: 4is not becausebuildCacheis turned on, but rather because the Nuxt productionbuildDiris located withinnode_modules/.cache/nuxt. It is also possible for users to configure this even withoutcompatibilityVersion: 4and your module should ideally handle both cases.However, the fix is simple. Instead of using a hard-coded relative path, you can compute the path relative to
nuxt.options.buildDirandnuxt.options.serverDir... Or, you could use an absolute path or even a Nuxt alias.I hope this helps 🙏
Let me know if there's anything else I can help with - and thank you for your work on those modules ❤️
dulnan commentedon Sep 21, 2024
Thank you very much for the explanation! I gave it a try with computing the correct relative path using the
relativeutil. That did not work unfortunately.I have reduced the example to the absolute minimum, with no complex relative imports at all. I am now generating 2 templates, the existing
serverOptionsfile and a file that exports the type. I'm no longer importing anything from the project's serverDir.This is the generated file that imports the type from a file in the same folder:
And the error is still the same:
frasza commentedon Sep 23, 2024
Might not be related, but I found out that my CI docker builds are also failing due to compat 4 option -> #29098
dulnan commentedon Oct 19, 2024
After some more digging I think that generating a
.tsfile withaddTemplateis likely something that just happened to work previously, but isn't really supported. I looked at various modules and the Nuxt repository itself and haven't found anyone else doing this. The workaround (or likely "proper" way anyway) is to split each template into two, one.mjsand one.d.tsfile. Basically only generate non-TS files that can be properly bundled. I will update my modules accordingly.danielroe commentedon Nov 4, 2024
I think the issue here is likely that we don't transpile the buildDir by default (if it's in node_modules, which it is for
compatibilityVersion: 4).This should be fixed in Nuxt.
dulnan commentedon Mar 21, 2025
Just ran into this problem again, this time because I'm adding a template with the
.tsextension where the source is provided by a third party library. There is no easy way for me to split this into two templates with separate.jsand.d.tsfiles. I tried pushing the path of the generated template tonuxt.options.build.transpile, however that did not work. Is there a potential workaround I could do until it's fixed?7 remaining items
Gwynerva commentedon May 12, 2026
@danielroe With
addTemplateandwrite: truethere is a way to write full TypeScript template with runtime code and types together and use both types and runtime code in Nuxt App.However, the server side has no access to templates added via
addTemplate. Attempting to bypass this by creating an alias to such a template throws an error during the build — Rolldown complains about the TS code (although it works fine in dev mode). Additionally,addServerTemplatehas nowriteproperty and does not seem to be detected by the project's TypeScript system, resulting in the error: "Cannot find module ... or its corresponding type declarations."Is support for TypeScript templates on the server side planned?
It is really annoying to manually split everything into
.mjsand.d.tsfiles, and it requires a lot of extra effort to make Nitro pick up these types...danielroe commentedon May 12, 2026
@Gwynerva you expose types to your nitro + nuxt apps like this:
does that work for you?
Gwynerva commentedon May 12, 2026
@danielroe
In my module setup I have:
In server plugin I have:
It still errors of missing types but at least the console log works in dev mode.
Changing the extension to
.tsor.jsor none at all breaks server and errors "unknown module, treating as external" so the docs there should be corrected as well: https://nuxt.com/docs/4.x/api/kit/templates#creating-a-virtual-file-for-nitroI tried to fix all this like a week ago and figured out you need to manually configure
tsConfigfor types to work which is even worse: 3 actions needed to make TypeScript work on Nitro side. I dropped this idea and tried to trick Nitro with global Nuxt alias pointing toaddTemplatefile. Works in dev but breaks of TS code when building sadly.So no it does not work correctly, no TS support and it still requires painful manual splitting of code with duplicating content.
danielroe commentedon May 12, 2026
how did you manually configure
tsConfig? what do you mean by this?Gwynerva commentedon May 12, 2026
Can't remember right now, it was Claude doing this stuff, but I think it added additional
includefor.d.tswith types for Nitro server tsconfig or something like that.danielroe commentedon May 12, 2026
that is exactly what passing the second option:
{ nitro: true }does. (assuming you have the version of nuxt/kit that the feature is implemented in)Gwynerva commentedon May 12, 2026
Well I tried exactly this right now and it fails. I can create a new issue if you want like in 10 minutes.
Also worth noting that I use layers setup "base project" + ".playground" so maybe this breaks it.
I am using lastest Nuxt.
Gwynerva commentedon May 12, 2026
@danielroe I was able to reproduce it on clean latest Nuxt version without any layers involved: #35064
danielroe commentedon May 12, 2026
@Gwynerva I had another look and realised there was an issue with the content of the type template in the example I provided earlier.
I've provided a better example in the linked issue, which works.
fukcrz commentedon May 28, 2026
@danielroe
I can still reproduce a similar issue with Nuxt
4.4.5/ Nitro2.13.4.The root cause seems to be that Nuxt moves the production
buildDirundernode_modules/.cache/nuxt/.nuxtwhen.nuxtalready exists.In Nuxt
4.4.5, the related source is in:The relevant logic is:
Then
.tstemplates generated byaddTemplatealso live undernode_modules, and Nitro/Rollup seems to parse them as plain JS instead of transforming them as TS.The related Nitro source seems to be in:
where the esbuild transform excludes
node_modules:Example error:
RollupError: node_modules/.cache/nuxt/.nuxt/resources.ts (1:12): Expected ',', got '{' 1: import type { Permission } from "../../../../../auth/shared/utils/access" ^A temporary workaround is to explicitly set:
With this,
#buildstays in.nuxt, and the TS template parse error disappears.Leaving this here in case it helps clarify the failure mode. If this should be tracked as a separate Nuxt/Nitro issue, I can open one with a minimal reproduction.