Skip to main content
The Schema API provides JSON Schema-based validation with automatic type inference for Feathers services.

schema

Creates a schema wrapper that provides validation and type inference from a JSON Schema definition.
import { schema } from '@feathersjs/schema'

const userSchema = schema({
  $id: 'user',
  type: 'object',
  required: ['email', 'password'],
  properties: {
    email: { type: 'string' },
    password: { type: 'string' },
    age: { type: 'number' }
  }
} as const)

Parameters

definition
JSONSchemaDefinition
required
JSON Schema definition object with $id property
ajv
Ajv
default:"DEFAULT_AJV"
Custom AJV validator instance. Defaults to the built-in validator with coerceTypes: true

Returns

Returns a SchemaWrapper<S> instance with the following members:
validate
<T>(data: T) => Promise<T>
Validates data against the schema. Returns validated (possibly coerced) data or throws BadRequest error
properties
Record<string, JSONSchema>
The schema’s property definitions
required
readonly string[]
Array of required property names
definition
JSONSchemaDefinition
The original schema definition
_type
FromSchema<S>
Type inference helper (TypeScript only). Use with Infer<typeof schema> to extract the inferred type

Types

JSONSchemaDefinition

Extends standard JSON Schema with required $id property:
type JSONSchemaDefinition = JSONSchema & {
  $id: string
  $async?: true
  properties?: { [key: string]: JSONSchema }
  required?: readonly string[]
}

Validator

A validation function type:
type Validator<T = any, R = T> = (data: T) => Promise<R>

Infer

Extract the TypeScript type from a schema:
import { Infer } from '@feathersjs/schema'

const mySchema = schema({ /* ... */ } as const)
type MyType = Infer<typeof mySchema>

Combine

Combine a schema type with additional properties:
import { Combine } from '@feathersjs/schema'

type UserWithId = Combine<typeof userSchema, { id: number }>

SchemaWrapper

The class returned by schema() that wraps a JSON Schema definition.

validate

Validates and coerces data according to the schema:
try {
  const validated = await userSchema.validate({
    email: '[email protected]',
    password: 'secret',
    age: '25' // Will be coerced to number
  })
} catch (error) {
  // BadRequest with validation errors
}
data
any
required
Data to validate
Returns: Promise<T> - Validated and coerced data Throws: BadRequest - If validation fails

toJSON

Returns the underlying schema definition:
const definition = userSchema.toJSON()

DEFAULT_AJV

The default AJV instance used by schemas:
import { DEFAULT_AJV } from '@feathersjs/schema'

// Configuration:
// - coerceTypes: true
// - addUsedSchema: false

addFormats

Add format validators to an AJV instance:
import { Ajv, addFormats } from '@feathersjs/schema'

const ajv = new Ajv()
addFormats(ajv, ['email', 'uri', 'date-time'])

const schema = schema(definition, ajv)

Parameters

ajv
Ajv
required
AJV instance to add formats to
formats
FormatName[] | FormatsPluginOptions
Array of format names or configuration object

Example Usage

Basic Schema

import { schema, Infer } from '@feathersjs/schema'

const messageSchema = schema({
  $id: 'message',
  type: 'object',
  required: ['text'],
  additionalProperties: false,
  properties: {
    id: { type: 'number' },
    text: { type: 'string' },
    userId: { type: 'number' },
    createdAt: { type: 'string', format: 'date-time' }
  }
} as const)

type Message = Infer<typeof messageSchema>

Custom Validation

import { Ajv, schema, addFormats } from '@feathersjs/schema'

const ajv = new Ajv({
  coerceTypes: true,
  removeAdditional: true
})

addFormats(ajv, ['email', 'uri'])

const userSchema = schema({
  $id: 'user',
  type: 'object',
  properties: {
    email: { type: 'string', format: 'email' },
    website: { type: 'string', format: 'uri' }
  }
} as const, ajv)

With Service

import { schema, Infer } from '@feathersjs/schema'
import { hooks } from '@feathersjs/schema'

const userDataSchema = schema({
  $id: 'user-data',
  type: 'object',
  required: ['email', 'password'],
  properties: {
    email: { type: 'string', format: 'email' },
    password: { type: 'string', minLength: 8 }
  }
} as const)

type UserData = Infer<typeof userDataSchema>

app.service('users').hooks({
  before: {
    create: [hooks.validateData(userDataSchema)]
  }
})

Build docs developers (and LLMs) love