---
description: Learn the different types and options available in Triplit schemas.
---

import { Callout } from 'nextra-theme-docs';

# Data types

When using a schema you have a few datatypes at your disposal:

### Schema type

The schema type is used to define a collection and its attributes. It should always be the outermost type in your schema definition. It is a special type of Record type so may use the same modifiers as [Record](#record).

```typescript
import { Schema as S } from '@triplit/client';
const schema = {
  todos: {
    schema: S.Schema({
      id: S.Id(),
      // Additional attributes here...
    }),
  },
};
```

### Value types

Value types are basic primitive types for the database.

#### String

The string data type is used to store text.

```typescript
import { Schema as S } from '@triplit/client';
const stringType = S.String();
```

Strings support `=`, `!=`, `like`, `nlike`, `in`, `nin`, and `isDefined` operators in `where` statements.

##### `like` and `nlike`

You can use the `like` operator in a where clause to do simple filtering with string similarity. A `like` expression is true if the supplied attribute matches the supplied filter pattern.

An underscore (`_`) in a pattern stands for (matches) any single character; a percent sign (`%`) matches any sequence of zero or more characters.

For example:

```typescript
['triplit', 'like', 'triplit']    true
['triplit', 'like', 'tri%']       true
['triplit', 'like', 'tr_pl_t']    true
['triplit', 'like', 'trip']       false
```

##### `in` and `nin`

You can use the `in` operator in a where clause to check if an attribute is in a set of values. The `nin` operator is the opposite of `in`.

For example:

```typescript
['triplit', 'in', ['triplit', 'hello']]    true
['triplit', 'nin', ['triplit', 'hello']]   false
```

#### Number

The number data type is used to store integer or float numbers.

```typescript
import { Schema as S } from '@triplit/client';
const numberType = S.Number();
```

Numbers support `=`, `!=`, `>`, `>=`, `<`, `<=`, `in`, `nin`, and `isDefined` operators in `where` statements.

#### Boolean

The boolean data type is used to store true or false values.

```typescript
import { Schema as S } from '@triplit/client';
const booleanType = S.Boolean();
```

Booleans support `=`, `!=`, and `isDefined` operators in `where` statements.

#### Date

The date data type is used to store date and time values.

```typescript
import { Schema as S } from '@triplit/client';
const dateType = S.Date();
```

Dates support `=`, `!=`, `>`, `>=`, `<`, `<=`, and `isDefined` operators in `where` statements.

#### Options

Value types have a few options that can be passed to their constructor.

##### `nullable`

You can indicate an attribute is nullable by passing the `{ nullable: true }` option to its constructor.

```typescript
import { Schema as S } from '@triplit/client';
import { TriplitClient } from '@triplit/client';
const schema = {
  test: {
    schema: S.Schema({
      id: S.Id(),
      nullableString: S.String({ nullable: true }),
    }),
  },
};

const client = new TriplitClient({
  schema,
});

await client.insert('test', {
  nullableString: null,
});
```

##### `default`

You can provide defaults values or functions for an attribute. Triplit currently support literal values and the following functions:

- `uuid()`
- `now()`

The below schema has literal and function default values.

```typescript
import { Schema as S } from '@triplit/client';
import { TriplitClient } from '@triplit/client';
const schema = {
  messages: {
    schema: S.Schema({
      id: S.Id(),
      text: S.String({ default: 'hello' }),
      sent_at: S.Date({ default: S.Default.now() }),
    }),
  },
};
await client.insert('test', {});
// { id: <uuid>, text: 'hello', sent_at: '2021-03-01T00:00:00.000Z' }
```

##### `enum` (String only)

You can provide an array of strings to the `enum` option to restrict the possible values of a string attribute.

```typescript
import { Schema as S } from '@triplit/client';
const schema = {
  test: {
    schema: S.Schema({
      id: S.Id(),
      status: S.String({ enum: ['active', 'inactive'] as const }),
    }),
  },
};
```

This will both perform runtime validation and provide autocomplete in your editor. **Note: you must add `as const` to the array to enable Typescript support for the enum values.**

### Set

Set types are used to store a collection of non nullable value types. Sets are unordered and do not allow duplicate values.

<Callout type="info" emoji="ℹ️">
  Lists, which support ordering and duplicate values, are on the
  [roadmap](https://triplit.dev/roadmap).
</Callout>

```typescript
import { Schema as S } from '@triplit/client';
const stringSet = S.Set(S.String());
```

Sets support `has` and `!has` operators in `where` statements, which check if the set does or does not contain the value. They also support the `isDefined` operator.

### Record

Record types support nested information.

```typescript
import { Schema as S } from '@triplit/client';
const recordType = S.Record({
  street: S.String(),
  city: S.String(),
  state: S.String(),
  zip: S.String(),
});
```

### Optional

You may mark attributes in a schema (and record) as optional with the `Optional` modifier. They will not be required by the schema and will be undefined at runtime if not provided. Optional attributes may also be deleted and assigned to `undefined` in updater functions.

```typescript {7}
import { Schema as S } from '@triplit/client';

const schema = S.Schema({
  address: {
    schema: {
      street: S.String(),
      apartmentNumber: S.Optional(S.String()),
      city: S.String(),
      state: S.String(),
      zip: S.String(),
    },
  },
});

/*
Will be valid:
{
  street: '123 Main St',
  city: 'Anytown',
  state: 'NY',
  zip: '12345',
}

Will also be valid:
{
  street: '123 Main St',
  city: 'Anytown',
  state: 'NY',
  zip: '12345',
  apartmentNumber: '2',
}
*/
```

Optional attributes support the `isDefined` operator, which checks if the specified attribute is defined.

```typescript
import { Schema as S } from '@triplit/client';
const schema = {
  profiles: {
    schema: S.Schema({
      id: S.Id(),
      name: S.String(),
      email: S.Optional(S.String()),
    }),
  },
};

const query = client
  .query('profiles')
  .where('email', 'isDefined', true)
  .build();
```
