Open Studio
Kit

Lifecycle hooks

Every kubb:* hook a build fires, its payload, and when it fires. Listen with kubb.hooks.hook(name, handler) or from a plugin's hooks map.

Kubb runs on one shared, typed hook emitter, and every phase of a build fires a kubb:* hook on it. Plugins listen through their hooks map. Outside code listens through kubb.hooks.

Every hook name and its payload lives in the KubbHooks type. Handlers can be async, and Kubb awaits each one.

Listening ​

Attach a listener with kubb.hooks.hook(name, handler) before you call build().

ts
import { createKubb } from 'kubb'

const kubb = createKubb({
  input: './petStore.yaml',
  output: { path: './gen' },
})

kubb.hooks.hook('kubb:plugin:end', ({ plugin, duration }) => {
  console.log(`${plugin.name} finished in ${duration}ms`)
})

kubb.hooks.hook('kubb:build:end', ({ files }) => {
  console.log(`Generated ${files.length} files`)
})

await kubb.build()

Firing order ​

A full generation run fires the hooks in this order.

Generation run ​

These wrap a full run. A direct .build() or .safeBuild() does not fire them.

HookPayloadWhen it fires
kubb:lifecycle:start{ version }The bundler plugin starts, before anything else
kubb:generation:start{ config }A run begins, before setup
kubb:setup:startnoneBefore the driver and storage are initialized
kubb:setup:endnoneAfter setup, before the build pipeline
kubb:generation:end{ config, storage, status, diagnostics, filesCreated, hrStart }The run finishes, after the output passes
kubb:lifecycle:endnoneThe bundler plugin is done

Build pipeline ​

These come from the pipeline, so .build() and .safeBuild() fire them too.

HookPayloadWhen it fires
kubb:plugin:setupKubbPluginSetupContextOnce per plugin during setup, to register generators, resolvers, macros, and options
kubb:build:start{ config, adapter, meta, getPlugin, files, upsertFile }The AST is ready, before plugins run. Skipped when no adapter parsed input
kubb:plugin:start{ plugin }Before a plugin's generators run
kubb:generate:schema(node, ctx)For each schema node the adapter produced
kubb:generate:operation(node, ctx)For each operation node
kubb:generate:operations(nodes, ctx)Once with every operation node
kubb:plugin:end{ plugin, duration, success, error, config, files, upsertFile }After a plugin finishes, with its timing and a file snapshot
kubb:plugins:end{ config, files, upsertFile }After every plugin has generated, before files hit disk. The spot to add aggregate files like a barrel
kubb:files:processing:start{ files }Before the batch of generated files is written
kubb:files:processing:update{ files }As files are written. Here files holds progress records ({ processed, total, percentage, source?, file, config }), not the FileNode array the :start and :end variants carry
kubb:files:processing:end{ files }After the batch is written
kubb:build:end{ files, config, outputDir }After every file is written

Output passes ​

These run after a successful build, only during a full generation run.

HookPayloadWhen it fires
kubb:format:startnoneBefore the formatter runs
kubb:format:endnoneAfter formatting
kubb:lint:startnoneBefore the linter runs
kubb:lint:endnoneAfter linting
kubb:hooks:startnoneBefore the postGenerate commands run
kubb:hook:start{ id, command, name, args }Before one postGenerate command runs
kubb:hook:lineKubbHookLineContextFor each output line a postGenerate command emits
kubb:hook:endKubbHookEndContextAfter one postGenerate command finishes
kubb:hooks:endnoneAfter every postGenerate command

Messaging ​

These carry log messages and diagnostics, and can fire at any point.

HookPayloadWhen it fires
kubb:info{ message, info }An informational message
kubb:success{ message, info }A step completed successfully
kubb:warn{ message, info }A non-fatal problem
kubb:error{ error, meta }An unstructured error, so its stack survives
kubb:diagnostic{ diagnostic }A structured diagnostic (warning, info, or an update notice)