CipherStash Docs

Schema definition

Define which columns to encrypt, what queries to support, and how to handle nested objects

Schema definition

Schemas tell the SDK which database columns to encrypt and what types of queries to support on the encrypted data.

Creating schema files

Declare your encryption schema in TypeScript — either in a single file or split across multiple files:

src/protect/
└── schema.ts          # single file
src/protect/schemas/
├── users.ts           # per-table files
└── posts.ts

Defining a schema

A schema maps your database tables and columns using encryptedTable and encryptedColumn:

schema.ts
import { encryptedTable, encryptedColumn } from "@cipherstash/stack/schema"

// TypeScript name        Database table name
//     ↓                       ↓
export const protectedUsers = encryptedTable("users", {
  // TypeScript name    Database column name
  //     ↓                    ↓
  email: encryptedColumn("email"),
})

Index types

Index types determine what queries you can run on encrypted data. Methods are chainable — call as many as you need on a single column.

schema.ts
export const protectedUsers = encryptedTable("users", {
  email: encryptedColumn("email")
    .equality()        // exact match queries
    .freeTextSearch()  // full-text search
    .orderAndRange(),  // sorting and range queries
})
MethodPurposeSQL equivalent
.equality()Exact match lookupsWHERE email = 'user@example.com'
.freeTextSearch()Full-text / fuzzy searchWHERE description LIKE '%example%'
.orderAndRange()Sorting, comparison, range queriesORDER BY price ASC
.searchableJson()Encrypted JSONB path and containment queriesWHERE metadata @> '{"role":"admin"}'

Only enable the indexes you need — each additional index type has a performance cost.

For columns storing JSON data, .searchableJson() is the recommended index. It automatically configures the column for encrypted JSONB path and containment queries. See Searchable encryption for details.

Data types

Use .dataType() to specify the plaintext type for a column:

schema.ts
encryptedColumn("age").dataType("number").orderAndRange()

Supported data types: 'string', 'number', 'boolean', 'date', 'bigint', 'json'.

Free-text search options

Customize the tokenizer and filter settings for .freeTextSearch():

schema.ts
encryptedColumn("bio").freeTextSearch({
  tokenizer: { kind: "ngram", token_length: 3 },  // or { kind: "standard" }
  token_filters: [{ kind: "downcase" }],
  k: 6,
  m: 2048,
  include_original: false,
})

Nested objects

CipherStash Encryption supports nested objects in your schema, allowing you to encrypt nested properties. You can define nested objects up to 3 levels deep using encryptedField.

Searchable encryption is not supported on nested objects. This is most useful for NoSQL databases or less structured data.

schema.ts
import { encryptedTable, encryptedColumn, encryptedField } from "@cipherstash/stack/schema"

export const protectedUsers = encryptedTable("users", {
  email: encryptedColumn("email").equality().freeTextSearch(),
  profile: {
    name: encryptedField("profile.name"),
    address: {
      street: encryptedField("profile.address.street"),
      location: {
        coordinates: encryptedField("profile.address.location.coordinates"),
      },
    },
  },
})

When working with nested objects:

  • Each level can have its own encrypted fields
  • The maximum nesting depth is 3 levels
  • Null and undefined values are supported at any level
  • Optional nested objects are supported

Encrypted JSONB

For columns that store JSON objects, use .searchableJson() to enable encrypted JSONB queries:

schema.ts
const documents = encryptedTable("documents", {
  metadata: encryptedColumn("metadata").searchableJson(),
})

This enables both JSONPath selector queries and containment queries on the encrypted data.

Multiple tables

Pass multiple schemas when initializing the client:

protect/index.ts
import { Encryption } from "@cipherstash/stack"

const client = await Encryption({ schemas: [protectedUsers, documents] })

Type inference

Infer plaintext and encrypted types from your schema:

schema.ts
import type { InferPlaintext, InferEncrypted } from "@cipherstash/stack/schema"

type UserPlaintext = InferPlaintext<typeof protectedUsers>
// { email: string; ... }

type UserEncrypted = InferEncrypted<typeof protectedUsers>
// { email: Encrypted; ... }

Client-safe exports

For client-side code where the native FFI module is not available, import schema builders from the @cipherstash/stack/client subpath:

schema.ts
import { encryptedTable, encryptedColumn } from "@cipherstash/stack/client"

This exports schema builders and types only — no native module dependency.

On this page