---
title: "Smart Coercion Plugin"
description: "Automatically coerce request and response values to match your schema types without writing manual coercion logic."
sidebar:
  label: "Smart Coercion"
---

:::warning
This plugin improves developer experience, but it adds runtime overhead. For performance sensitive applications or complex schemas, manual coercion in your validation layer is usually more efficient.
:::

## Installation

```package-install
npm install @orpc/json-schema@beta
```

## Setup

Use `SmartCoercionHandlerPlugin` in your handler to coerce incoming request data to the expected `.input` schema:

```ts
import { SmartCoercionHandlerPlugin } from '@orpc/json-schema'

const handler = new OpenAPIHandler(router, {
  plugins: [
    new SmartCoercionHandlerPlugin({
      converters: [
        new ZodToJsonSchemaConverter(),
        // Add other schema converters as needed
      ],
    })
  ]
})
```

Use `SmartCoercionLinkPlugin` in your link to coerce server responses to the expected `.output` or `.errors` schemas:

```ts
import { SmartCoercionLinkPlugin } from '@orpc/json-schema'

const link = new OpenAPILink(contract, {
  plugins: [
    new SmartCoercionLinkPlugin(contract, {
      converters: [
        new ZodToJsonSchemaConverter(),
        // Add other schema converters as needed
      ],
    }),
  ]
})
```

:::info
This plugin relies on [JSON Schema Converters](/docs/openapi/specification#json-schema-converters) to determine how values should be coerced. Configure the appropriate converter for each validation library you use. If a required converter is unavailable, it automatically falls back to [Standard Json Schema](https://standardschema.dev/json-schema) conversion.
:::

## How It Works

The plugin coerces values safely by following these rules:

1. **Schema-driven:** Converts only when the schema defines the target type
2. **Safe only:** Converts only values with an unambiguous, lossless representation, such as `'123'` to `123`
3. **Preserve original values:** Leaves the original value unchanged when conversion would be unsafe
4. **Union-aware:** Tries to determine the best union branch to use for conversion
5. **Deep conversion:** Applies recursively inside nested objects and arrays

:::info
JSON Schema does not natively represent `BigInt`, `Date`, `RegExp`, `URL`, `Set`, or `Map`. For these types, oRPC relies on `x-native-type` metadata in your schema:

- `x-native-type: 'bigint'` for BigInt
- `x-native-type: 'date'` for Date
- `x-native-type: 'regexp'` for RegExp
- `x-native-type: 'url'` for URL
- `x-native-type: 'set'` for Set
- `x-native-type: 'map'` for Map

Since this field is not part of the official JSON Schema specification, custom converters must set it themselves. The built-in [ZodToJsonSchemaConverter](/docs/integrations/zod#json-schema-converter), [ValibotToJsonSchemaConverter](/docs/integrations/valibot#json-schema-converter), and [ArkTypeToJsonSchemaConverter](/docs/integrations/arktype#json-schema-converter) already handle it for you.
:::

## Conversion Rules

### String → Boolean

Supports these specific string values, case-insensitively:

- `'true'`, `'on'` → `true`
- `'false'`, `'off'` → `false`

:::info
HTML `<input type="checkbox">` elements commonly submit `'on'` or `'off'`, so this conversion is especially useful for form handling.
:::

### String → Number

Supports valid numeric strings:

- `'123'` → `123`
- `'3.14'` → `3.14`

### String/Number → BigInt

Supports integer strings and whole numbers:

- `'12345678901234567890'` → `12345678901234567890n`
- `123` → `123n`

### String → Date

Supports ISO 8601 date and datetime strings:

- `'2023-10-01'` → `new Date('2023-10-01')`
- `'2020-01-01T06:15'` → `new Date('2020-01-01T06:15')`
- `'2020-01-01T06:15Z'` → `new Date('2020-01-01T06:15Z')`
- `'2020-01-01T06:15:00Z'` → `new Date('2020-01-01T06:15:00Z')`
- `'2020-01-01T06:15:00.123Z'` → `new Date('2020-01-01T06:15:00.123Z')`
- `'2020-01-01T06:15:00-07:00'` → `new Date('2020-01-01T06:15:00-07:00')`

### String → RegExp

Supports valid regular expression strings:

- `'/^\\d+$/i'` → `new RegExp('^\\d+$', 'i')`
- `'/abc/'` → `new RegExp('abc')`

### String → URL

Supports valid URL strings:

- `'https://example.com'` → `new URL('https://example.com')`

### Array → Set

Supports arrays of **unique values**:

- `['apple', 'banana']` → `new Set(['apple', 'banana'])`

### Array → Object

Converts arrays into objects with numeric keys:

- `['apple', 'banana']` → `{ 0: 'apple', 1: 'banana' }`

:::info
This is particularly useful for [Bracket Notation](/docs/openapi/bracket-notation#limitations) when you need objects with numeric keys.
:::

### Array → Map

Supports arrays of key-value pairs with **unique keys**:

- `[['key1', 'value1'], ['key2', 'value2']]` → `new Map([['key1', 'value1'], ['key2', 'value2']])`

## Advanced Usage

You can also use this plugin in guides such as [Expanding Type Support for OpenAPI Link](/docs/advanced/expanding-type-support-for-openapi-link).

## Learn More

For implementation details, see the [SmartCoercionHandlerPlugin source code](https://github.com/middleapi/orpc/blob/main/packages/json-schema/src/smart-coercion-handler-plugin.ts), the [SmartCoercionLinkPlugin source code](https://github.com/middleapi/orpc/blob/main/packages/json-schema/src/smart-coercion-link-plugin.ts), or the [coercer source code](https://github.com/middleapi/orpc/blob/main/packages/json-schema/src/coercer.ts).
