Skip to main content
The schema defines the structure of documents in your Orama database. It specifies which fields are searchable and what type of data each field contains.

Schema Definition

Define a schema by mapping property names to their types:
import { create } from '@orama/orama'

const db = await create({
  schema: {
    title: 'string',
    description: 'string',
    price: 'number',
    inStock: 'boolean',
    category: 'enum'
  }
})

Supported Types

Orama supports the following field types:

Scalar Types

TypeTypeScript TypeDescriptionExample
stringstringFull-text searchable text"Wireless Headphones"
numbernumberNumeric values with range queries99.99
booleanbooleanTrue/false valuestrue
enumstring | numberEnumerated values (exact match)"electronics"
geopoint{ lat: number, lon: number }Geographic coordinates{ lat: 40.7128, lon: -74.0060 }

Array Types

All scalar types (except geopoint) support array variants:
const db = await create({
  schema: {
    tags: 'string[]',        // Array of strings
    ratings: 'number[]',      // Array of numbers
    features: 'boolean[]',    // Array of booleans
    categories: 'enum[]'      // Array of enums
  }
})

Vector Types

For semantic search and similarity matching:
const db = await create({
  schema: {
    title: 'string',
    embedding: 'vector[1536]'  // 1536-dimensional vector
  }
})
The number in brackets specifies the vector dimension. All vectors for a given property must have the same dimension.

Nested Objects

Schemas support nested object structures:
const db = await create({
  schema: {
    title: 'string',
    author: {
      name: 'string',
      email: 'string',
      verified: 'boolean'
    },
    metadata: {
      created: 'number',
      tags: 'string[]'
    }
  }
})

Searching Nested Properties

Use dot notation to search nested properties:
const results = await search(db, {
  term: 'john',
  properties: ['author.name', 'author.email']
})

Filtering Nested Properties

const results = await search(db, {
  term: 'database',
  where: {
    'author.verified': true,
    'metadata.created': { gte: 1640000000 }
  }
})

Type Inference

Orama provides full TypeScript type inference for your schema:
import { create, insert, search } from '@orama/orama'

const db = await create({
  schema: {
    title: 'string',
    price: 'number',
    inStock: 'boolean'
  }
})

// TypeScript knows the document structure
await insert(db, {
  title: 'Laptop',      // ✓ string
  price: 999.99,        // ✓ number
  inStock: true         // ✓ boolean
  // unknownField: 'x'  // ✗ TypeScript error
})

const results = await search(db, {
  term: 'laptop'
})

// TypeScript knows the result structure
results.hits[0].document.title   // ✓ string
results.hits[0].document.price   // ✓ number

Schema Type Mappings

From types.ts:67-92, here’s how schema types map to TypeScript types:
type SchemaTypes<Value> = 
  Value extends 'string' ? string :
  Value extends 'string[]' ? string[] :
  Value extends 'boolean' ? boolean :
  Value extends 'boolean[]' ? boolean[] :
  Value extends 'number' ? number :
  Value extends 'number[]' ? number[] :
  Value extends 'enum' ? string | number :
  Value extends 'enum[]' ? (string | number)[] :
  Value extends 'geopoint' ? Point :
  Value extends `vector[${number}]` ? number[] :
  Value extends object ? { [Key in keyof Value]: SchemaTypes<Value[Key]> } :
  never

String vs Enum

Choose the right type for your use case:

Use string for:

  • Full-text search
  • Content that should be tokenized
  • Text with multiple words
  • Fuzzy matching
schema: {
  title: 'string',        // "Wireless Bluetooth Headphones"
  description: 'string'   // "High-quality audio with..."
}

Use enum for:

  • Exact matching
  • Categories and tags
  • Single-word values
  • Filtering without tokenization
schema: {
  category: 'enum',       // "electronics"
  status: 'enum',         // "active"
  priority: 'enum'        // 1, 2, 3
}

Schema Validation

Orama validates documents against the schema during insertion:
const db = await create({
  schema: {
    title: 'string',
    price: 'number'
  }
})

// ✓ Valid document
await insert(db, {
  title: 'Product',
  price: 29.99
})

// ✗ Invalid: price should be number
await insert(db, {
  title: 'Product',
  price: '29.99'  // Error: type mismatch
})

Custom Validation

You can provide a custom validation function:
const db = await create({
  schema: { /* ... */ },
  components: {
    validateSchema: (doc, schema) => {
      // Return property name if invalid, undefined if valid
      if (doc.price && doc.price < 0) {
        return 'price'
      }
      return undefined
    }
  }
})

Searchable vs Sortable

All schema properties are searchable by default. For sorting configuration, see the Database page.
Array properties (string[], number[], etc.) cannot be used for sorting. Enum and geopoint types also cannot be sorted.

Schema Immutability

Schemas are immutable after database creation. You cannot add or remove properties from an existing database.
To modify a schema:
  1. Create a new database with the updated schema
  2. Export data from the old database
  3. Import data into the new database
import { create, insertMultiple, search } from '@orama/orama'

// Old database
const oldDb = await create({
  schema: { title: 'string', price: 'number' }
})

// Get all documents
const allDocs = await search(oldDb, { term: '' })

// New database with updated schema
const newDb = await create({
  schema: {
    title: 'string',
    price: 'number',
    category: 'enum'  // New field
  }
})

// Migrate data
await insertMultiple(newDb, allDocs.hits.map(hit => ({
  ...hit.document,
  category: 'default'
})))

Next Steps

Documents

Learn how to insert and manage documents

Search

Start searching your data

Build docs developers (and LLMs) love