Schemas
Schemaful vs Schemaless
Providing a schema to Triplit is optional, but it is recommended in order to take advantage of all the features provided by Triplit.
Limitations of schemaless mode include:
- You are limited to exclusively using storing value types that are supported by JSON: string, number, boolean, objects, null.
- If you use Typescript, you will not get type checking for your queries and results.
- Access control rules are defined in schemas, and thus are not supported in schemaless mode.
Defining your schema
A schema object defines your collections and the attributes and relationships on those collections. Schemas are defined in Javascript like so:
import { Schema as S } from '@triplit/client';
import { TriplitClient, ClientSchema } from '@triplit/client';
const schema = {
todos: {
schema: S.Schema({
id: S.Id(),
text: S.String(),
complete: S.Boolean(),
created_at: S.Date(),
tags: S.Set(S.String()),
}),
},
users: {
schema: S.Schema({
id: S.Id(),
name: S.String(),
address: S.Record({
street: S.String(),
city: S.String(),
state: S.String(),
zip: S.String(),
}),
}),
},
} satisfies ClientSchema;
const client = new TriplitClient({
schema,
});
Passing a schema to the client constructor will override any schema currently stored in your cache. This can cause data corruption, if the new schema is not compatible with existing data in the shape of the old schema. Refer to the schema management guide for more information.
By default, your schema file will be created by triplit init
or npm create triplit-app
in your project directory at triplit/schema.ts
. If you need to
save your schema file somewhere else, you can specify that path with the
TRIPLIT_SCHEMA_PATH
environmental variable and the Triplit CLI commands will
refer to it there.
id
Every collection in Triplit must define an id
field in its schema. The S.Id()
data type will generate a random id
by default upon insertion. If you want to specify the id
for each entity, you may pass it as a string in to the insert
method as shown below.
// assigning the id automatically
await client.insert('todos', {
text: 'get tortillas',
complete: false,
created_at: new Date(),
tags: new Set([groceries]),
})
// assigning the id manually
await client.insert('todos', {
id: 'tortillas'
text: 'get tortillas',
complete: false,
created_at: new Date(),
tags: new Set([groceries]),
})
Getting types from your schema
While the schema
passed to the client constructor will be used to validate your queries and give you type hinting in any of the client's methods, you may want to extract the types from your schema to use in other parts of your application.
Entity
You can extract a simple type from your schema with the Entity
type.
import { Entity, ClientSchema } from '@triplit/client';
const schema = {
todos: {
schema: S.Schema({
id: S.Id(),
text: S.String(),
complete: S.Boolean(),
created_at: S.Date(),
tags: S.Set(S.String()),
}),
},
} satisfies ClientSchema;
type Todo = Entity<typeof schema, 'todos'>;
/*
Todo will be a simple type:
{
id: string,
text: string,
complete: boolean,
created_at: Date,
tags: Set<string>
}
*/
EntityWithSelection
If you need more advanced types you can use the EntityWithSelection
type. It expands Entity
with a selected
type parameter that can be used to select out specific attributes and an inclusion
type parameter to add the types of related entities.
import type { Entity, EntityWithSelection } from '@triplit/client';
const schema = {
users: {
schema: S.Schema({
id: S.Id(),
name: S.String(),
posts: S.RelationMany('posts', {
where: [['authorId', '=', '$1.id']],
}),
}),
},
posts: {
schema: S.Schema({
id: S.Id(),
text: S.String(),
authorId: S.String(),
}),
},
};
type User = Entity<typeof schema, 'users'>;
/*
type User = {
id: string;
name: string;
}
*/
type UserWithPosts = EntityWithSelection<
typeof schema,
'users',
['name'],
{ posts: true }
>;
/*
type UserWithPosts = {
name: string;
posts: Array<{
id: string;
text: string;
}>
}
*/
QueryResult
If you'd like to extract types from a query instead of a schema, you can use the QueryResult
type.
import { client } from './client';
import type { QueryResult } from '@triplit/client';
const userQuery = client
.query('users')
.select(['name'].include('posts'))
.build();
type UserQueryResult = QueryResult<typeof userQuery>;
/*
type UserQueryResult = {
name: string;
posts: Array<{
id: string;
text: string;
}>
}
*/
Reading your schema
Your schema is available in your codebase in the triplit/schema.ts
file. However you may locally edit the schema, or you may not be aware of remote edits that have happened to the schema. To view the current state of the server's schema, run:
triplit schema print -l remote -f file
See CLI docs or run triplit schema print --help
for more options.