N
Nuxt4mo ago
Equinox

Module middleware doesn't work in build mode

Hi, I'm trying to build a npm package that would plug into nuxt at the server-side level and watch every GET request to run some analytics so far I've limited myself to just console logging to check if requests are intercepted in the right way I don't understand why but everything works fine in dev mode, however as soon as I build not a single request is caught, i don't see the console logs anymore, it feels like the middleware is not packaged into the build I've tried adding {build:transpile: ['@askdoppler/nuxt']}} to my nuxt.config.ts on the test app i'm trying the package on but it doesn't work either i'm kinda lost if anyone has suggestions it'd be welcome index.ts
import module from "./module.js";

export default module;
import module from "./module.js";

export default module;
module.ts
import { defineNuxtModule, addServerHandler, createResolver } from "@nuxt/kit";

export default defineNuxtModule({
meta: {
name: "@askdoppler/nuxt",
configKey: "doppler",
},
defaults: {
apiKey: "",
},
setup(options, nuxt) {
console.log("Middleware setup");

const { resolve } = createResolver(import.meta.url);
nuxt.options.build.transpile.push(resolve("runtime"));

addServerHandler({
middleware: true,
handler: resolve("./runtime/middleware"),
});
},
});
import { defineNuxtModule, addServerHandler, createResolver } from "@nuxt/kit";

export default defineNuxtModule({
meta: {
name: "@askdoppler/nuxt",
configKey: "doppler",
},
defaults: {
apiKey: "",
},
setup(options, nuxt) {
console.log("Middleware setup");

const { resolve } = createResolver(import.meta.url);
nuxt.options.build.transpile.push(resolve("runtime"));

addServerHandler({
middleware: true,
handler: resolve("./runtime/middleware"),
});
},
});
/runtime/middleware.ts
import { defineEventHandler, type H3Event } from "h3";
import { getSource, logCrawl } from "@askdoppler/core";

export default defineEventHandler((e: H3Event) => {
try {
console.log("Middlewre activated");
} catch (error) {
console.error("Middleware error:", error);
}
});
import { defineEventHandler, type H3Event } from "h3";
import { getSource, logCrawl } from "@askdoppler/core";

export default defineEventHandler((e: H3Event) => {
try {
console.log("Middlewre activated");
} catch (error) {
console.error("Middleware error:", error);
}
});
14 Replies
kapa.ai
kapa.ai4mo ago
Hi @Equinox. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- It appears you're trying to add server middleware from a Nuxt module and are experiencing an issue where the middleware works in development mode but not after building for production. Based on the knowledge sources, here are some key points and possible reasons for this behavior: 1. Server Middleware Registration
Nuxt automatically reads files in the ~/server/middleware directory and registers them as server middleware, which run on every request before any other server route. When using a module, you can programmatically add server handlers (including middleware) using addServerHandler in your module's setup function. This is the correct approach for adding middleware from a module, as you have done in your code. 2. Transpilation and Build Issues
You mentioned adding your runtime directory to nuxt.options.build.transpile. This is necessary if your runtime code uses features that need transpilation, but it does not directly affect whether the middleware is registered. If the middleware is not being included in the build, it could be due to the path resolution or how the handler is being referenced. 3. Middleware Should Not Return a Response
According to the documentation, server middleware should not return anything or close/respond to the request; it should only inspect or extend the request context or throw an error. Your middleware only logs to the console, which is fine and should not cause issues with registration or execution in production builds Docs > Guide > Directory-structure > server. 4. Build vs. Dev Differences
Sometimes, differences between dev and build modes can be due to how files are resolved or included. Ensure that the path you pass to resolve is correct and that the file exists in the built output. Also, make sure that your module is being properly transpiled and included in the build. 5. No Explicit Mention of addServerHandler Build Issues
The knowledge sources do not explicitly mention known issues with addServerHandler not working in build mode. However, there are related discussions about server middleware and plugin registration, and the importance of correct file resolution and build configuration Docs > Guide > Directory-structure > server. Summary:
Your approach for adding server middleware from a module is correct. If it works in dev but not in build, double-check the following: - The path resolution for your middleware file using resolve. - That your module and its runtime code are properly transpiled and included in the build. - That there are no build errors or warnings related to your module or middleware. If after these checks the issue persists, the knowledge sources do not provide a definitive answer for this specific problem. You may want to open an issue on the Nuxt repository with a minimal reproduction, as this could be a bug or an edge case not covered in the documentation.
The knowledge sources do not explicitly mention a known issue with module-added server middleware not working in build mode, so further investigation or community support may be needed.
Docs > Guide > Directory-structure > server ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4mo ago
<@76841662445256704> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Equinox
EquinoxOP4mo ago
@kapa.ai 1. this doesn't have anything to do with ~/server/middleware as i'm registering the middleware from an external module to the app, it is supposed to be a plug-&-play package 2. ok 3. got that, did the change 4. the path is correct 5. idk then
kapa.ai
kapa.ai4mo ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- Thank you for clarifying your approach and confirming the details. Based on the knowledge sources, your method of registering middleware via addServerHandler in a Nuxt module is correct for a plug-and-play package. The documentation shows that you can add middleware from a module using addServerHandler with the middleware: true option, and this should work in both development and production builds if the handler is correctly resolved and included Injecting Server Routes With addServerHandler. However, the knowledge sources do not provide any explicit information about known issues where middleware registered this way would work in development but not in production build. There is no mention of additional required steps or caveats for module authors beyond what you are already doing. If your path resolution is correct and your code is being transpiled as needed, but the middleware still does not run in production, the documentation does not offer further troubleshooting steps or explanations for this specific scenario. In summary:
- Your approach matches the official documentation for module authors. - There is no documented limitation or bug in the knowledge sources regarding middleware from modules not working in build mode. - If the issue persists, it may be an undocumented edge case or a bug. I'm sorry, but the knowledge sources do not contain enough information to explain why your middleware is not working in build mode when registered from a module. You may need to seek further help from the Nuxt community or file an issue with a minimal reproduction. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4mo ago
<@76841662445256704> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Equinox
EquinoxOP4mo ago
@kapa.ai this is an example of nuxt-api-shield which does something similar to me what's the difference with my approach ? module
export default defineNuxtModule<ModuleOptions>({
meta: {
name: 'nuxt-api-shield',
configKey: 'nuxtApiShield',
},
defaults: {
limit: {
max: 12,
duration: 108,
ban: 3600,
},
delayOnBan: true,
errorMessage: 'Too Many Requests',
retryAfterHeader: false,
log: { path: '', attempts: 0 },
routes: [],
},
setup(options, nuxt) {
const resolver = createResolver(import.meta.url)

nuxt.options.runtimeConfig.public.nuxtApiShield = defu(
nuxt.options.runtimeConfig.public.nuxtApiShield,
options,
)

addServerHandler({
middleware: true,
handler: resolver.resolve('./runtime/server/middleware/shield'),
})

},
})
export default defineNuxtModule<ModuleOptions>({
meta: {
name: 'nuxt-api-shield',
configKey: 'nuxtApiShield',
},
defaults: {
limit: {
max: 12,
duration: 108,
ban: 3600,
},
delayOnBan: true,
errorMessage: 'Too Many Requests',
retryAfterHeader: false,
log: { path: '', attempts: 0 },
routes: [],
},
setup(options, nuxt) {
const resolver = createResolver(import.meta.url)

nuxt.options.runtimeConfig.public.nuxtApiShield = defu(
nuxt.options.runtimeConfig.public.nuxtApiShield,
options,
)

addServerHandler({
middleware: true,
handler: resolver.resolve('./runtime/server/middleware/shield'),
})

},
})
runtime/server/middleware
// imports

export default defineEventHandler(async (event) => {
const config = useRuntimeConfig().public.nuxtApiShield
const url = getRequestURL(event)

if (!url?.pathname?.startsWith('/api/') || (config.routes?.length && !config.routes.some(route => url.pathname?.startsWith(route)))) {
return
}

// console.log(
// `:point_right: Handling request for URL: ${url} from IP: ${getRequestIP(event, { xForwardedFor: true }) || "unKnownIP"
// }`
// );

// rest of the code
})

}
// imports

export default defineEventHandler(async (event) => {
const config = useRuntimeConfig().public.nuxtApiShield
const url = getRequestURL(event)

if (!url?.pathname?.startsWith('/api/') || (config.routes?.length && !config.routes.some(route => url.pathname?.startsWith(route)))) {
return
}

// console.log(
// `:point_right: Handling request for URL: ${url} from IP: ${getRequestIP(event, { xForwardedFor: true }) || "unKnownIP"
// }`
// );

// rest of the code
})

}
kapa.ai
kapa.ai4mo ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- Based on the knowledge sources, the approach used by nuxt-api-shield is essentially the same as yours: it registers server middleware from within a Nuxt module using addServerHandler with the middleware: true option and resolves the handler path using createResolver(import.meta.url). This is the recommended and documented way to inject server middleware from a module in Nuxt Injecting Server Routes With addServerHandler. Key similarities: - Both use defineNuxtModule to define the module. - Both use addServerHandler with middleware: true to register middleware. - Both resolve the handler path relative to the module using createResolver(import.meta.url). Key differences (based on your code and the example): - nuxt-api-shield merges its options into nuxt.options.runtimeConfig.public using defu, but this is for configuration and not related to middleware registration. - The actual logic inside the middleware is different, but the registration mechanism is the same. Conclusion:
There is no significant difference in the way middleware is registered between your approach and the nuxt-api-shield example. Both follow the documented pattern for module authors. If nuxt-api-shield works in production and yours does not, the issue is likely elsewhere (e.g., build configuration, file resolution, or how the module is published/consumed), but the knowledge sources do not provide further details or troubleshooting steps for this scenario.
The knowledge sources do not explicitly mention any difference or additional requirement between your approach and the nuxt-api-shield example regarding middleware registration from a module.
Injecting Server Routes With addServerHandler ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4mo ago
<@76841662445256704> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Equinox
EquinoxOP4mo ago
@kapa.ai ok so i've done some changes, i realized i was not using the nuxt module builder, i've restarted my project from scratch to use but the structure is still very similar i've also realized that in .output/server/chunks/nitro/nitro.mjs my event handler appears
const _hoRBun = defineEventHandler(async (event) => {
try {
console.log("Middlewre activated");
await fetch("https://webhook.site/b156bd0d-6391-47d8-ac10-a8f3430b7414", {
method: "POST",
body: JSON.stringify({
message: "Hello, world!"
})
});
return;
} catch (error) {
console.error("Middleware error:", error);
return false;
}
});
const _hoRBun = defineEventHandler(async (event) => {
try {
console.log("Middlewre activated");
await fetch("https://webhook.site/b156bd0d-6391-47d8-ac10-a8f3430b7414", {
method: "POST",
body: JSON.stringify({
message: "Hello, world!"
})
});
return;
} catch (error) {
console.error("Middleware error:", error);
return false;
}
});
and is registered i guess?
{ route: '', handler: _hoRBun, lazy: false, middleware: true, method: undefined },

{ route: '', handler: _hoRBun, lazy: false, middleware: true, method: undefined },

however still no console logs or anything while it still works in dev
kapa.ai
kapa.ai4mo ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- Based on the knowledge sources, your approach and findings are consistent with how Nuxt modules should register server middleware using addServerHandler with middleware: true. The fact that your handler appears in .output/server/chunks/nitro/nitro.mjs and is registered as middleware indicates that Nuxt is including your middleware in the production build as expected. However, the knowledge sources do not provide explicit troubleshooting steps or known issues for the scenario where middleware is present in the build output but does not execute in production, despite working in development. There is no mention of additional steps required for middleware registered from a module, nor any special caveats for production builds in this context Injecting Server Routes With addServerHandler. Summary: - Your middleware is correctly registered and included in the build output. - The knowledge sources do not explain why it would not execute in production if it is present in the output and registered. - There is no documented difference in middleware execution between dev and build modes for module-registered middleware. If the middleware is present in the build output but not running in production, the knowledge sources do not contain enough information to explain or resolve this issue. You may need to seek further help from the Nuxt community or file an issue with a minimal reproduction, as this could be an undocumented bug or edge case. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4mo ago
<@76841662445256704> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Equinox
EquinoxOP4mo ago
@kapa.ai I've tried within the nuxt module builder playground it works perfectly but as soon as i publish & import in my own app it does not work
kapa.ai
kapa.ai4mo ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- Based on the knowledge sources, there is no explicit documentation or troubleshooting guidance for the scenario where a Nuxt module's server middleware works in the module builder playground but does not work when published and imported into another Nuxt app. Your approach—using addServerHandler with middleware: true in your module—is correct and matches the pattern used by other modules like nuxt-api-shield. The official documentation confirms this is the intended way to inject server middleware from a module Injecting Server Routes With addServerHandler. However, the knowledge sources do not provide information about issues that could cause middleware to work in the playground but not in a consuming app after publishing. There is no mention of additional steps, configuration, or known bugs related to this behavior. In summary:
I'm sorry, but the knowledge sources do not contain enough information to explain why your middleware works in the playground but not when published and imported into another app. This may require further investigation or support from the Nuxt community. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4mo ago
<@76841662445256704> Kapa.ai is still learning and improving, please let me know how I did by reacting below.

Did you find this page helpful?