@alikhalilll/nuxt-auto-middleware
| Install | |
|---|---|
npm install @alikhalilll/nuxt-auto-middleware |
|
| Latest Version: | 1.2.0 |
| Vue: | 3 |
| License: | MIT |
| Last Updated: | Oct 5, 2026 |
| Links: | GitHub · npm |
@alikhalilll/nuxt-auto-middleware
Declarative, layout-based route middleware for Nuxt 3 / 4. Map layouts to middlewares once in your nuxt.config.ts — the module generates a single global route middleware that dispatches the right chain on each navigation.
- Layout → middleware mapping with glob patterns (
dashboard/*,admin*) or RegExp objects. - Named middleware groups for DRY configuration:
{ auth: ['auth', 'verify-role'] }referenced as@auth. - Per-page overrides via
definePageMeta({ middlewares: [...] })orskipAutoMiddleware: true. - Typed registry — the module generates a
AutoMiddlewareNameunion type and augmentsPageMeta, so typos are compile errors. - Early termination — a middleware returning
falsestops the chain; any other value is treated as a navigation result. - Zero runtime deps — just Nuxt.
Table of contents
- Install
- Register the module
- Usage
- Middleware return values
- Typed registry
- Matching rules
- Module options reference
- Exported types
Install
pnpm add @alikhalilll/nuxt-auto-middleware
Register the module
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@alikhalilll/nuxt-auto-middleware'],
autoMiddleware: {
groups: {
auth: ['auth', 'verify-role'],
},
rules: [
{ layouts: ['default'], middlewares: ['log-activity'] },
{ layouts: ['dashboard', 'dashboard/*'], middlewares: ['@auth'] },
{ layouts: ['admin'], middlewares: ['@auth', 'require-admin'] },
],
debug: false,
pageMetaField: 'middlewares', // set to false to disable per-page extras
},
});
Middleware files live in the standard Nuxt location: ~/middleware/auth.ts, ~/middleware/verify-role.ts, etc.
Usage
Basic mapping
One layout, one middleware — the simplest rule:
autoMiddleware: {
rules: [
{ layouts: ['default'], middlewares: ['track-pageview'] },
],
},
Any page using the default layout (explicitly, or implicitly — no layout in definePageMeta) will run ~/middleware/track-pageview.ts before rendering.
Named groups
Groups keep rules DRY when the same stack of middlewares is used from multiple layouts:
autoMiddleware: {
groups: {
auth: ['auth', 'verify-role'],
adminOnly: ['auth', 'verify-role', 'require-admin'],
},
rules: [
{ layouts: ['dashboard', 'dashboard/*'], middlewares: ['@auth'] },
{ layouts: ['admin', 'admin/*'], middlewares: ['@adminOnly'] },
],
},
Group references are expanded at build time. An unknown @group name throws during nuxt prepare, so typos don't silently ship.
Glob patterns
Layouts support * (non-slash), ** (any), and ? (one non-slash char):
rules: [
{ layouts: ['dashboard/*'], middlewares: ['@auth'] }, // dashboard/x, dashboard/y
{ layouts: ['admin/**'], middlewares: ['@adminOnly'] }, // admin/x, admin/x/y, ...
{ layouts: ['settings-?'], middlewares: ['verify-role'] }, // settings-a, settings-b
],
RegExp patterns
For anything more expressive, pass a RegExp directly:
rules: [
{ layouts: [/^(dashboard|portal)$/], middlewares: ['@auth'] },
{ layouts: [/^ops\//], middlewares: ['require-ops'] },
],
Per-page extras
Append additional middlewares for one page without changing global rules. The field name (middlewares by default) is configurable via pageMetaField:
<script setup lang="ts">
definePageMeta({
layout: 'dashboard',
middlewares: ['force-2fa'], // runs AFTER @auth resolved from the layout rule
});
</script>
Because the AutoMiddlewareName type is generated from your rules + groups, typos are compile-time errors.
Opt a page out entirely
<script setup lang="ts">
definePageMeta({
layout: 'dashboard',
skipAutoMiddleware: true, // no middleware runs, even though dashboard would match
});
</script>
Catch-all layout
Use ** to run middleware for every layout (except pages with layout: false or skipAutoMiddleware: true):
rules: [
{ layouts: ['**'], middlewares: ['track-pageview'] },
{ layouts: ['dashboard', 'admin'], middlewares: ['@auth'] },
],
When multiple rules match the same layout, their middlewares are concatenated in config order (duplicates are dropped).
Disabling per-page overrides
autoMiddleware: {
pageMetaField: false, // ignore definePageMeta({ middlewares: [...] })
rules: [ /* ... */ ],
},
The typed registry is still generated (so AutoMiddlewareName remains useful elsewhere); the dispatcher just doesn't look at page meta.
Debug logs
autoMiddleware: { debug: true, rules: [ /* ... */ ] }
With debug on, each navigation logs the resolved layout and the full ordered chain, plus whether any middleware returned false or a redirect.
Middleware return values
Middleware functions receive (to, from) exactly like standard Nuxt route middlewares:
| Return | Behaviour |
|---|---|
false |
Stop the chain, allow navigation. |
true / void |
Continue to the next middleware. |
| anything else | Treated as a navigation result — chain stops. |
Example: an auth middleware that redirects to /login when the cookie is missing, otherwise lets the chain continue:
// ~/middleware/auth.ts
export default defineNuxtRouteMiddleware(() => {
const token = useCookie('token').value;
if (!token) return navigateTo('/login');
// undefined → continue to the next middleware
});
Every middleware runs inside callWithNuxt(), so useNuxtApp() / composables work as usual.
Typed registry
The module emits #build/auto-middleware/types.d.ts with:
export type AutoMiddlewareName = 'auth' | 'verify-role' | 'require-admin' | 'log-activity';
…plus an augmentation that adds middlewares?: AutoMiddlewareName[] and skipAutoMiddleware?: boolean to PageMeta. Both are auto-included in the Nuxt-generated nuxt.d.ts, so you don't need to import anything. You can import the type if you're authoring outside of definePageMeta:
import type { AutoMiddlewareName } from '#build/auto-middleware/types';
const stack: AutoMiddlewareName[] = ['auth', 'verify-role'];
Matching rules
- A page with no explicit layout is treated as
default. - A page with
layout: falseis skipped entirely. - A page with
skipAutoMiddleware: trueis skipped entirely. - Layout pattern matching is anchored (
^...$) — partial matches do not count. - When multiple rules match, middlewares are concatenated in config order and deduped (first occurrence wins).
Module options reference
| Option | Type | Default | Purpose |
|---|---|---|---|
rules |
AutoMiddlewareRule[] |
[] |
Layout → middlewares mapping. Required. |
groups |
Record<string, string[]> |
{} |
Named reusable middleware lists, referenced via @name inside rules. |
debug |
boolean |
false |
Log resolution + execution at runtime. |
pageMetaField |
string | false |
'middlewares' |
Page-meta key used to append extra middlewares. Set to false to disable per-page overrides. |
Exported types
import type {
AutoMiddlewareOptions,
AutoMiddlewareRule,
} from '@alikhalilll/nuxt-auto-middleware/types';
License
MIT
Related Packages
Nuxt integrator for Qelos: server middleware/module that identifies the user and...
Nuxt module to add well-known files and rules with middlewares
Version History
| Version | Released | Vue | License |
|---|---|---|---|
| 1.2.0 | ^3.0 | MIT | |
| 1.1.1 | ^3.0 | MIT | |
| 1.1.0 | ^3.0 | MIT | |
| 1.0.3 | ^3.0 | MIT | |
| 1.0.2 | ^3.0 | MIT | |
| 1.0.1 | ^3.0 | MIT | |
| 1.0.0 | ^3.0 | MIT |