---
url: /docs/5.x/guide/going-further/printers.md
description: >-
  Printers turn Kubb's AST schema nodes into generated code. The printer option
  on plugin-ts, plugin-zod, and plugin-faker replaces the handler for a single
  schema type, so you change what one plugin emits without forking it.
---

# Override a printer

A printer runs inside a plugin's generator, not at the end of the pipeline. The [adapter](/docs/5.x/guide/concepts/adapters) turns a spec into the [AST](/docs/5.x/guide/concepts/ast), [macros](/docs/5.x/guide/going-further/macros) rewrite the nodes, and a printer turns each schema node into code for one output target. `@kubb/plugin-ts` prints TypeScript type nodes, `@kubb/plugin-zod` prints Zod expressions, and `@kubb/plugin-faker` prints Faker expressions. A [parser](/docs/5.x/guide/concepts/parsers) still has to turn the assembled file into source text, and [storage](/docs/5.x/guide/concepts/storage) writes it to disk, before the CLI's formatter, linter, and `postGenerate` commands run.

These three plugins expose their printer through a `printer.nodes` option, a partial map of schema types to handlers. A handler replaces the built-in output for one schema type, so you can print a `date` schema as the JavaScript `Date` object or append `.openapi(...)` metadata to every Zod object without forking the plugin.

## Shape

The map is keyed by the schema `type` discriminant, such as `'string'`, `'integer'`, `'date'`, `'enum'`, or `'object'`. Supply only the handlers you want to replace and the built-in ones fill in the rest.

```typescript [Type definition]
type PrinterNodes = Partial<{
  [K in SchemaType]: (this: Context, node: SchemaNodeByType[K]) => Output | null
}>
```

Handlers run with a `this` context, so write them as regular functions rather than arrow functions. `this.transform(node)` recurses into a nested schema node through the full handler map, overrides included. `this.base(node)` runs the built-in handler your override replaced, so you can wrap its output instead of rebuilding it. `this.options` reads the resolved printer options, such as `arrayType` on `@kubb/plugin-ts` or `direction` on `@kubb/plugin-zod`.

## TypeScript types

`@kubb/plugin-ts` builds TypeScript AST nodes, so a handler returns a `ts.TypeNode` created with the compiler's factory. This override prints `date` schemas as the JavaScript `Date` object instead of `string`.

```typescript [date.ts]
import ts from 'typescript'
import { pluginTs } from '@kubb/plugin-ts'

pluginTs({
  printer: {
    nodes: {
      date() {
        return ts.factory.createTypeReferenceNode('Date', [])
      },
    },
  },
})
```

## Zod schemas

`@kubb/plugin-zod` prints expression strings, so a handler returns the Zod code as a string. With `mini: true` the same overrides target the Zod Mini printer instead.

```typescript twoslash [date.ts]
import { pluginZod } from '@kubb/plugin-zod'

pluginZod({
  printer: {
    nodes: {
      date() {
        return 'z.iso.date()'
      },
    },
  },
})
```

Use `this.base` to keep the default output and decorate it. This override appends `.openapi(...)` to every object schema, and nested nodes still print through the regular handlers.

```typescript twoslash [openapi.ts]
import { pluginZod } from '@kubb/plugin-zod'

pluginZod({
  printer: {
    nodes: {
      object(node) {
        return `${this.base(node)}.openapi(${JSON.stringify({ description: node.description })})`
      },
    },
  },
})
```

A Zod handler can also read `this.options.direction`, which is `'decode'` while printing response schemas and `'encode'` while printing request bodies and parameters. Return a different expression per direction and the plugin treats the node as a two-way conversion, emitting an `${name}InputSchema` variant that request bodies resolve to. See [Encode a custom type on requests](/plugins/plugin-zod/recipes/encode-a-custom-type-on-requests).

## Faker mocks

`@kubb/plugin-faker` also prints strings, one Faker expression per schema node. This override generates floats where the spec declares integers.

```typescript twoslash [integer.ts]
import { pluginFaker } from '@kubb/plugin-faker'

pluginFaker({
  printer: {
    nodes: {
      integer() {
        return 'faker.number.float()'
      },
    },
  },
})
```

## Printer override or macro

A macro rewrites the node itself, before anything prints. Retype `integer` schemas to `string` with a macro and `plugin-ts`, `plugin-zod`, and `plugin-faker` all follow, because they print the rewritten node. A printer override changes what one plugin emits for a node type, leaving the node and every other plugin's output unchanged.

Reach for a printer override when the output cannot be described as another schema node. No schema node prints as `Date`, and none carries an `.openapi(...)` call, so a macro cannot produce either. When the printed code is fine and only its name or file location needs to change, reach for a [resolver](/docs/5.x/guide/going-further/resolvers) instead.

> \[!TIP]
> The two compose. The `macros` option on the same plugin rewrites nodes first, then the printer prints the result, overrides included.
