Skip to main content
The schema package in Orionjs provides a powerful type-safe way to define data structures in your application. Schemas serve two main purposes:
  1. Define data structures: Schemas describe the structure, types, and validation rules for your data models.
  2. Automatic integration: Schemas automatically integrate with GraphQL for API generation and MongoDB for document validation.

Structure and Naming

  • Use schemaWithName() function from @orion-js/schema
  • Follow naming conventions: {EntityName}Schema for the schema, {EntityName} for the type
  • Keep schemas focused on a single entity or concept
  • Put schemas in app/{component}/schemas/{EntityName}/index.ts
  • Prefer createEnum for enum types
  • Avoid big entities; split them into smaller ones and use composition
  • Use typedId() for MongoDB document IDs
  • Schema validation errors should be camelCase (e.g., priceMustBePositive)

Basic Usage

import {schemaWithName, InferSchemaType, createEnum} from '@orion-js/schema'
import {typedId} from '@orion-js/mongodb'

// Create a type-safe enum for product status
export const ProductStatusEnum = createEnum('ProductStatusEnum', [
  'draft',
  'active',
  'discontinued'
] as const)

// Create a typed ID for products
export const typedProductId = typedId('prd')
export type ProductId = typeof typedProductId.__tsFieldType

export const ProductSchema = schemaWithName('Product', {
  _id: {type: typedProductId},
  name: {type: String, label: 'Product Name', min: 3, max: 100},
  description: {type: String, optional: true},
  status: {type: ProductStatusEnum, defaultValue: 'draft'},
  price: {
    type: Number,
    validate: (value) => {
      if (value < 0) return 'priceMustBePositive'
    }
  },
  createdAt: {type: Date, defaultValue: () => new Date()}
})

// Infer the TypeScript type from your schema
export type Product = InferSchemaType<typeof ProductSchema>

// The type will be inferred as:
// type Product = {
//   _id: `prd-${string}`;
//   name: string;
//   description?: string;
//   status: "draft" | "active" | "discontinued";
//   price: number;
//   createdAt: Date;
// }

Nested Schemas

Create nested schemas for complex data structures:
import {schemaWithName, InferSchemaType} from '@orion-js/schema'

// Create a nested schema for product variants
export const ProductVariantSchema = schemaWithName('ProductVariant', {
  name: {type: String, label: 'Variant Name', min: 2},
  price: {type: Number, min: 0},
  sku: {type: String, optional: true}
})

export type ProductVariant = InferSchemaType<typeof ProductVariantSchema>

export const ProductSchema = schemaWithName('Product', {
  _id: {type: typedProductId},
  name: {type: String},
  variants: {type: [ProductVariantSchema], optional: true},
  tags: {type: [String], optional: true}
})

export type Product = InferSchemaType<typeof ProductSchema>

Integration with GraphQL

Schemas defined with schemaWithName are automatically converted to GraphQL types when used in your API:
import {Query, Resolvers, createQuery} from '@orion-js/graphql'
import {ProductSchema} from '../schemas/Product'

@Resolvers()
export class ProductResolvers {
  @Query()
  product = createQuery({
    params: {
      productId: {type: typedProductId}
    },
    returns: ProductSchema,
    resolve: async (params) => {
      return product
    }
  })
}
When the above resolver is registered, Orionjs automatically:
  • Creates a GraphQL type for ProductSchema
  • Sets up the appropriate field types based on your schema definition
  • Handles type conversions between your application and GraphQL

Integration with MongoDB

When using schemas with MongoDB collections, Orionjs automatically validates documents:
import {createCollection} from '@orion-js/mongodb'
import {ProductSchema} from '../schemas/Product'

const Products = createCollection({
  name: 'store.products',
  schema: ProductSchema
})

// Document will be automatically validated against ProductSchema
await Products.insertOne({
  name: 'Widget',
  price: 29.99,
  createdAt: new Date()
})

Common Schema Types

export const TypeExamplesSchema = schemaWithName('TypeExamples', {
  stringField: {type: String},          // Text values
  numberField: {type: Number},          // Numeric values (integers or floats)
  integerField: {type: 'integer'},      // Force whole numbers only
  booleanField: {type: Boolean},        // true/false values
  dateField: {type: Date},              // Date and time values
  emailField: {type: 'email'},          // Email with automatic validation
  dynamicField: {type: 'blackbox'},     // Any object without specific schema
  stringArrayField: {type: [String]}    // Array of strings
})

Property Options

Properties can be configured with the following options:
{
  // Core options
  type: String,                           // Required type definition
  label: 'Human-readable label',          // For UI and error messages
  description: 'Field description',       // For documentation
  optional: true,                         // Make field optional (default: false)
  private: true,                          // Hide from GraphQL API

  // Validation options
  min: 0,                                 // Min value/length
  max: 100,                               // Max value/length
  allowedValues: ['small', 'medium'],     // Restrict to allowed values

  // Default and transformation
  defaultValue: 'draft',                  // Static default
  defaultValue: () => new Date(),         // Dynamic default
  clean: (value) => value.trim(),         // Transform before validation

  // Custom validation
  validate: (value) => {
    if (someCondition) return 'errorCode' // camelCase error codes
  }
}

Next Steps

Explore more about schemas: