Middlewares
A middleware subscribes to lifecycle hooks and runs after every plugin handler for the same event. Plugins generate files, and middlewares observe and react to those files once they exist.
TIP
For barrel-file generation use the built-in @kubb/middleware-barrel. It is added by default when you import defineConfig from the top-level kubb package.
Quick start
Subscribe to kubb:plugins:end to inspect every generated file once all plugins have finished:
import { } from '@kubb/core'
export const = (() => ({
: 'middleware-log',
: {
'kubb:plugins:end'({ , }) {
.(`Generated ${.} files into ${..}`)
},
},
}))Wire it into your config:
import { } from 'kubb'
import { } from './logMiddleware.ts'
export default ({
: { : './petStore.yaml' },
: { : './src/gen' },
: [()],
})Anatomy
Every middleware returned from defineMiddleware has the following shape:
| Property | Type | Required | Purpose |
|---|---|---|---|
name | string | Yes | Unique middleware identifier. Convention is middleware-<id>. |
hooks | { [K in keyof KubbHooks]?: (...args: KubbHooks[K]) => void | Promise<void> } | Yes | Map of KubbHooks handlers. Each handler runs after all plugin handlers for that event. |
defineMiddleware takes a factory function and returns a callable. The factory runs once per build, so per-build state belongs in the closure:
import { } from '@kubb/core'
export const = (() => {
let = 0
return {
: 'middleware-count',
: {
'kubb:plugin:end'() {
++
},
'kubb:plugins:end'({ }) {
.(`${} plugins ran, ${.} files produced`)
},
},
}
})IMPORTANT
Middleware handlers always run last for any given event, after every plugin handler has completed. This guarantees that files is the full set when kubb:plugins:end fires.
Hooks
| Hook | Fires | Context |
|---|---|---|
kubb:plugin:end | After each individual plugin | { plugin, duration, success, error?, config, files, upsertFile } |
kubb:plugins:end | After all plugins have run | { files, config, upsertFile } |
Use kubb:plugin:end to track which plugins ran. Use kubb:plugins:end when you need the full file list, for barrel generation, manifests, audit logs, and notifications.
Call upsertFile(...files) inside kubb:plugins:end to add or merge files into the build output, the same way a generator does.
Naming convention
Middlewares follow the same layout as plugins and parsers:
| Surface | Pattern | Example |
|---|---|---|
| npm package | @<scope>/middleware-<name> or kubb-middleware-<name> | @kubb/middleware-barrel |
| Middleware runtime name | middleware-<name> (kebab-case, lowercase) | 'middleware-barrel' |
| Factory export | middleware<Name> (camelCase) | middlewareBarrel |
| Name constant | middleware<Name>Name | middlewareBarrelName |
Export the runtime name as a satisfies-typed constant so other code can reference it without typos:
import { } from '@kubb/core'
import type { } from '@kubb/core'
export const = 'middleware-example' satisfies ['name']
export const = (() => ({
: ,
: {
'kubb:plugins:end'({ }) {
.(`Total files: ${.}`)
},
},
}))Built-in middlewares
@kubb/middleware-barrel
Generates index.ts barrel files for every plugin output directory and a root barrel at output.path/index.ts. Already enabled when you use defineConfig from kubb. See the @kubb/middleware-barrel reference for the full option list.
bun add -d @kubb/middleware-barrelpnpm add -D @kubb/middleware-barrelnpm install --save-dev @kubb/middleware-barrelyarn add -D @kubb/middleware-barrel| Export | Purpose |
|---|---|
middlewareBarrel | Middleware factory that emits barrel files based on output.barrel. |
middlewareBarrelName | Stable string identifier ('middleware-barrel'). |
Configure it explicitly only when you need to customise barrel behaviour:
import { } from 'kubb'
import { } from '@kubb/middleware-barrel'
export default ({
: { : './petStore.yaml' },
: { : './src/gen', : { : 'named' } },
: [()],
})NOTE
Valid barrel.type values are 'all' and 'named'. At the plugin level, set barrel: { type: 'named', nested: true } for hierarchical barrels, or barrel: false to opt out for that plugin.
Creating a custom middleware
Use defineMiddleware from @kubb/core. The example below writes a manifest.json that lists every plugin that ran and every file the build produced:
import { } from '@kubb/core'
import { , , } from '@kubb/ast'
export const = ((: { ?: `${string}.json` } = {}) => {
const = . ?? 'manifest.json'
const = new <string>()
return {
: 'middleware-manifest',
: {
'kubb:plugin:end'({ }) {
.(.)
},
'kubb:plugins:end'({ , , }) {
const = {
: [...],
: .(() => .),
}
(
({
: ,
: `${..}/${}`,
: [({ : [(.(, null, 2))] })],
}),
)
},
},
}
})Register it in kubb.config.ts:
import { } from 'kubb'
import { } from './manifestMiddleware.ts'
export default ({
: { : './petStore.yaml' },
: { : './src/gen' },
: [({ : 'kubb.manifest.json' })],
})Examples
Add a banner to every generated file
import { } from '@kubb/core'
export const = ((: { : string }) => ({
: 'middleware-banner',
: {
'kubb:plugins:end'({ }) {
for (const of ) {
. = `/* ${.} */\n${. ?? ''}`
}
},
},
}))