import Script from 'next/script'; export default function App { return } </> ); } --- description: Learn how to setup user auth for your Triplit application with Clerk. --- import { Steps, Callout, Tabs, Tab } from 'nextra/components'; # Using Clerk with Triplit  is a user authentication and management service that makes it easy to add user accounts to your application. It's super simple to get Clerk up and running with Triplit, and this guide will show you how. <Callout> This guide assumes you have a Triplit project set up. If you don't have one, you can create one by following the  guide. </Callout> <Steps> ### Create a Clerk account and application Follow the official  to create an account and application in their dashboard. ### Get your Clerk public key We also need to configure Triplit to validate the JWT tokens issued by Clerk. To do this, we need the RSA public key for your Clerk application. You can find this in the **API Keys** section of the Clerk dashboard. ! Then click on the **Show JWT Public Key** button to reveal the public key. ! For local dev, add this to your `.env` file in your Triplit app, making sure to remove any newlines:  ### Start the Triplit development server Now that we've configured Clerk and added the necessary environmental variables, we can start the Triplit development server:  ### Add Clerk to your Triplit app You can add Clerk to your Triplit app by installing the appropriate SDK. Clerk has official support for , , , , and more. There are also community SDKs for frameworks like , , and . See the  for the full list of integrated frameworks. ### Add the Clerk token to your Triplit client Your Triplit client needs to send the JWT token issued by Clerk with each request. You can do this with the `startSession` method for the `TriplitClient`.  You'll note that we're using `setInterval` to automatically refresh the token before it expires. Triplit will close down connections with expired tokens, but this will keep connections open for as long as Clerk issues a token that has consistent  . ### Test locally Run you Triplit app and sign in with Clerk. If you’re setup correctly, you should see the connection is established and your data is syncing with your server. If you can't connect, ensure that you set the `TRIPLIT_EXTERNAL_JWT_SECRET` environmental variables correctly. ### Configure your Triplit dashboard To use Clerk with a deployed Triplit server, you just need ensure that it can use the Clerk public key to verify incoming requests. If you're using the Triplit Dashboard, you can add the public key to the **External JWT secret** input in your project settings. ! If you're using a custom self-hosted server, you need to set the `EXTERNAL_JWT_SECRET` environmental variable to the public key. ### Add access control to your schema Now that you have a user auth system set up, you can add roles and permissions to your Triplit schema. By default, the JWT issued by Clerk will set the `sub` claim to the authenticated user's unique identifier. In Triplit, you can use it to set up a simple `user` role:  . </Steps> --- description: Learn how to add authentication and authorization to your Triplit project. --- # Authentication and Authorization Authentication is the process of verifying the identity of a user. This usually involves a user providing some form of credentials  to a service, which then validates those credentials and provides a way to identify the user in future requests. This identity can be used to determine what data the user has access to ). ## Authentication Triplit uses  to communicate user identity. Authentication  itself should be handled by an authentication service outside of Triplit. This could be a third-party service like , , , , , etc or a custom service built by your team. The JWT will need to be signed with a proper signature. Triplit supports both symmetric  and asymmetric  encryption algorithms for JWTs. If you are using Triplit's hosted offering , then you will need to provide the JWT's signing secret or public key to Triplit in the `External JWT secret` field in your project's settings. If you are self-hosting Triplit, you will need to provide the signing secret or public key when you start the server with the `EXTERNAL_JWT_SECRET` environmental variable. The JWT should usually have some user-identifying information ), which can be accessed by Triplit to handle  that user. For backwards compatibility, Triplit reads the following claims: - `x-triplit-user-id`: The user's unique identifier. This is assigned to the variable `$session.SESSION_USER_ID` in queries. ### Tokens Triplit provides two basic tokens that are available in your project : - `anon` token: A token that represents an anonymous user. This token is safe to use on a client side device and should be used when no user is logged in. - `service` token: This token is used for administrative purposes and should only be used in trusted environments like a server you control. This token will bypass all access control checks. When getting started with Triplit these are fine to use, but they don't specify which application user is accessing the database, or if they have a distinct access role. This information can be configured by providing a JWT with the proper claims and signature . Triplit's flexible design allows you to define any JWT claims you would like. ### Using your tokens When you instantiate a `TriplitClient`, you can provide an initial token to authenticate with the server. This token is used to determine what data the client has access to.  This will automatically connect the client to the server and authenticate with the provided token. If you would like to connect manually, you can set `autoConnect` to `false` and call `client.connect` when ready.  ### Modeling sign in and sign out flows #### Starting sessions If users in your app start in an unauthenticated state , or if users can sign out, you will need to use Triplit's sessions API to initiate and teardown sync connections and the appropriate moments. When changing users , you should use the `startSession` method.  This will update the token and connect the client to the server. The `TriplitClient` calls this method implicitly when you provide a token to the constructor. For more information on the `startSession` method, see the . #### Ending sessions When a user signs out, you should call the `endSession` method. This will disconnect the client and reset metadata related to the session. It **will not** clear any data stored in the client's cache. It's up to you, the developer, to decide whether or not the next user should have access to the data from the previous user.  For more information on the `endSession` method, see the . #### Updating sessions If your authentication provider issues short-lived tokens, you may need to refresh the token mid-session. Read more about refreshing a session in the . ## Authorization Triplit allows you to define rules on your collections that determine who can read and write data. This is usually based on the tokens you provide. See  for more information on reading your tokens in queries and access control definitions. --- description: Learn how to setup user auth for your Triplit application with Supabase Auth. --- import { Steps, Callout, Tabs, Tab } from 'nextra/components'; # Using Supabase Auth with Triplit  is one of the services in the Supabase ecosystem that makes it easy to manage user accounts and authentication in your application. This guide will show you how to set up Supabase Auth with Triplit. <Callout> This guide assumes you have a Triplit project set up. If you don't have one, you can create one by following the  guide. </Callout> <Steps> ### Create a Supabase account and project Use the  to create an account and a project. This will setup a Postgres database and a Supabase Auth instance for your project. ### Get the JWT Secret for your Supabase project We also need to configure Triplit to validate the JWT tokens issued by Supabase. To do this, we need the JWT signing secret for your Supabase project. You can find this in the **JWT Settings** panel section of the **API Settings** panel. ! For local dev, add this to your `.env` file in your Triplit app:  ### Start the Triplit development server Now that we've configured Supabase and added the necessary environmental variables, we can start the Triplit development server:  ### Add Supabase Auth to your Triplit app Your app should have some flow to  that uses Supabase's authentication methods. Once a user is signed in, your Triplit client needs to send the JWT token issued by Supabase with each request, and handle other authentication events.  Generally you'll want to run `getSessionAndSubscribe` when your app loads and then unsubscribe from the session changes when your app unmounts.  ### Test locally Run you Triplit app and sign in with Supabase Auth. If you’re setup correctly, you should see the connection is established and your data is syncing with your server. If you can't connect, ensure that you set the `TRIPLIT_EXTERNAL_JWT_SECRET` environmental variables correctly. ### Configure your Triplit dashboard To use Supabase Auth with a deployed Triplit server, you just need ensure that it can use the Supabase JWT Secret to verify incoming requests. If you're using the Triplit Dashboard, you can add the JWT Secret to the **External JWT secret** input in your project settings. ! If you're using a custom self-hosted server, you need to set the `EXTERNAL_JWT_SECRET` environmental variable to the public key. ### Add access control to your schema Now that you have a user auth system set up, you can add roles and permissions to your Triplit schema. By default, the JWT issued by Supabase will set the `sub` claim to the authenticated user's unique identifier. It will also have the `role: 'authenticated'` claim. In Triplit, you can write a matcher object that will set up a simple `user` role:  . </Steps> --- description: Learn how to use the `triplit clear` command to clear a database. --- # `triplit clear` --- description: Use the `triplit dev` command to start a local Triplit development environment. --- # triplit dev --- description: The Triplit CLI provides a suite of tools to manage your Triplit projects, from local development to deployment. --- import { Tabs, Tab } from 'nextra-theme-docs'; # Installing the Triplit CLI Install the CLI in your project: <Tabs items={}> <Tab>  </Tab> <Tab>  </Tab> <Tab>  </Tab> <Tab>  </Tab> </Tabs> All commands in the CLI can be inspected by adding the `--help` flag. For example, to see the available commands: --- description: Learn how to use the `triplit init` command to add Triplit dependencies and configuration files to an existing project. --- # `triplit init` --- description: Learn how to use the `triplit repl` command to start an interactive REPL with the Triplit client. --- # triplit repl --- description: Learn how to use the `triplit roles` command to debug the roles and permissions of a JWT authentication token with your schema. --- # `triplit roles` ## `triplit roles eval` --- description: Learn how to use the `triplit schema ` commands to update or introspect the schema on a remote server. --- # `triplit schema` Read our guide on  for more information. ## `triplit schema push`  ## `triplit schema print`  ## `triplit schema diff` --- description: Learn how to use the `triplit seed ` commands to create and apply seed data files for Triplit databases. --- # `triplit seed` Read our guide on  for more information. ## `triplit seed create`  ## `triplit seed run` --- description: Learn how to use the `triplit snapshot ` commands to save a local copy of a remote Triplit database. --- # `triplit snapshot` ## `triplit snapshot create`  ## `triplit snapshot push` --- description: Learn the various debugging tools available for the Triplit client. --- import Image from 'next/image'; import BrowserConsoleClientImage from '../../../public/browser-console-client.png'; # Debugging ## Logging Triplit uses a configurable logger to log information about the client and underlying database's state, as well as the results of fetches and mutations. By default the logger is set to `'info'` level, but supports `'warn' | 'error' | 'debug'` as well. You can set the logger level by passing a `logLevel` option to the `TriplitClient` constructor:  If you'd like to save and export logs, you must set the `logLevel` to `'debug'`. You can then access the logs and relevant metadata from the `TriplitClient` instance:  ## Inspecting a client in the browser The `TriplitClient` class can be accessed from your browser console by adding the following code to an application that uses the `TriplitClient`:  This will make the `client` object available in the browser console, allowing you to inspect the state of the client and call methods on it, e.g. with `client.fetch`. <Image style={{ marginTop: 10 }} alt="browser console" src={BrowserConsoleClientImage} /> --- description: How to use the TriplitClient delete method to delete an entity. --- # delete `delete` deletes a record from a collection. For example: --- description: How to subscribe to various Triplit sync events to debug your app and remedy sync failures. --- # Event listeners The `TriplitClient` provides a number of event listeners that you can use to debug your app and remedy sync failures. These listeners are: ## Sync write failures These handlers are called when a write fails to sync with the server because of data corruption, a failed schema check, or insufficient write permissions. ### `onEntitySyncError` Given an the id of an entity and its collection, this handler is called when a write for that entity fails to sync with the server. The callback will provide an error and the specific change for the entity . It will be called repeatedly until the returned unsubscribe handler is called. You may choose to undo the write by calling `clearPendingChangesForEntity` or retry the write by mutating the entity again. The sync will automatically retry when any write to the entity or any other entity is made.  ### `onFailureToSyncWrites` When registered, the handler will be called when any write fails to sync. The callback provides an error object and the buffer of writes  that failed to sync. It will be called repeatedly until the returned unsubscribe handler is called. You may choose to undo the write by calling `clearPendingChangesAll`, or by calling `clearPendingChangesForEntity` for each entity that failed to sync. The sync will automatically retry when any write to the entity or any other entity is made.  ## Sync write success ### `onEntitySyncSuccess` Given an the id of an entity and its collection, this handler is called when a write for that entity successfully syncs with the server. It will be called repeatedly  until the returned unsubscribe handler is called.  ## Auth events ### `onSessionError` Read more about this listener in the  documentation. ## Message events The client communicates with the server over WebSockets. You can listen to messages sent and received with the following handlers: ### `onSyncMessageSent` When registered, the provided callback will fire with the message sent to the server. It will be called repeatedly until the returned unsubscribe handler is called.  ### `onSyncMessageReceived` When registered, the provided callback will fire with the message received from the server. It will be called repeatedly until the returned unsubscribe handler is called. --- description: How to use the TriplitClient fetchById method to query an entity by its primary key. --- # fetchById `fetchById` queries for a single entity by its id and returns the entity if it is found or `null` if it is not. For example:  This is a convenient shorthand for applying a `Where` filter and extracting the result from the result set. --- description: How to use the TriplitClient fetchOne method to query a single entity. --- import { Callout } from 'nextra-theme-docs'; # fetchOne `fetchOne` is similar to `fetch` but will return only the first entity in the result set or `null` if the result set is empty. For example:  This is a convenient shorthand for using the  `.Limit` and extracting the result from the result set. --- description: How to use the TriplitClient fetch method to query data. --- import { Callout } from 'nextra-theme-docs'; # fetch `fetch` executes the specified query and returns an array of entities. For example:  ## Fetch options Because a Triplit Client may be dealing with two databases , the exact nature of how you would like to query those is customizable. If no options are provided, queries will be fulfilled with the options `{ policy: 'local-first' }`. ### Policy The `policy` option determines how you interact with your local and remote databases. <Callout type="info" emoji="ℹ️"> This is distinct from the  parameter on a query, which indicates how you wish to query your local database. </Callout> The following policy types are valid: - `local-first`:  This policy will fetch data directly from the local database, however if is determined that the query cannot be fulfilled it will fetch data from the remote database. If the remote database fails to fulfill the query, the cached data is used. - `local-only`: This policy will fetch data directly from the local database and will never go to the network. - `remote-first`: This policy will fetch data from the remote database and update the local database with those results before querying the local database. - `local-and-remote`: This policy will fetch data from the local database and will fetch results from the remote database in the background and update the local database with those results. Optionally you may provide a `timeout` parameter, which informs Triplit to wait `timeout` milliseconds for the remote result to update the local database. <Callout type="warning"> `remote-only` has been deprecated and will be removed in a future release. If you need to fetch data from the remote database only, use . </Callout> - `remote-only`: This policy will fetch data directly from the remote database and will not update the local database with results. Results using this policy will also not include any data from the local database - notably any data that has been updated locally but not yet synced. This policy is not available on subscriptions. # HTTP clients ## `TriplitClient.http` You can access the HTTP API through the `http` property on the `TriplitClient` instance. It provides methods for fetching, inserting, updating, and deleting entities in your database. Any queries using this API will bypass the local cache and and mutations will not cause optimistic updates. If you have live queries syncing with the remote database, the Remote API will trigger these queries to update once the server confirms the changes.  ## `HttpClient` If you're only interested in talking to Triplit with the Remote API, and forgo local caching and optimistic updates altogether, you can use the `HttpClient` class directly. --- description: How to setup and use the TriplitClient in the browser to sync data. --- # Triplit Client Triplit is most powerful when it is used to sync data across multiple devices and users. Every Triplit Client is equipped with a sync engine that is responsible for managing the connection to the server and syncing data between your local database and remote database. ## Installation  ## Client and Server model As the monicker, "a full-stack database" implies, Triplit has components that run on both the client and the server. In particular, each client has its own database that is fully queryable just like the remote database. Thus, any query can be immediately fulfilled by the client without needing to go to the network. The client database is kept in sync with the remote database by setting up subscriptions to queries. Along with reads, every client is able to write to its database and Triplit ensures the write is propagated to the remote database and other listening clients. Because writes go directly to the client database, your application gets an optimistic effect to all of its writes. ### Client Database On the client, Triplit keeps your data in two storage areas: an `outbox` and a `cache`. The outbox is a buffer of data that is waiting to be sent to the server. The cache is a local copy of the data that has been confirmed to have been received by the server. By default, results from the cache and outbox are merged together, however queries can be configured to only return data from the cache  or only return data from the outbox . If a client is offline or is not connected to the remote database for any reason, then the data will remain in the outbox so that data can be synced at a later time. ### Server Database The server database provides durable centralized storage for clients and handles propagating writes to other listening clients. As well, the server acts as an authoritative figure for data as needed. For example, access control rules are checked on the server and unauthorized updates are rejected and not propagated. ## Setting up sync To set up syncing, you need to tell your Triplit Client how to connect to the remote database with the `serverUrl` and `token` options in the constructor. Additional options can be found .  ## Example  the Triplit CLI, you can run the following command to start a local Triplit Server :  By default this will set up a server at `http://localhost:6543`, and should display an access token for your database. You can run this script in multiple browser tabs to simulate multiple users/devices connecting and sending data. --- description: How to use the TriplitClient insert method to subscribe to create new data. --- import { Callout } from 'nextra-theme-docs'; # insert `insert` inserts a new record into a collection and returns the inserted record, if successful. For example:  The `id` field in Triplit is a special field that is used to uniquely identify records and is required on entities. If you do not provide an id, one will be generated for you. The `insert` method may also be used to upsert an existing record when used in a schemaless database or in conjunction with . For example:  <Callout emoji="⚠️"> When using `insert` to upsert an existing record, any defaults on the schema will be applied even if the record already exists. </Callout> --- description: Learn the options available to configure your TriplitClient. --- import { Callout } from 'nextra/components'; # Client configuration ## DB options These options define your local cache. - `schema` is a hard coded schema for your local cache - `storage` determines the storage engines for your local cache ) ## Sync options These options define how you want to sync with the server. - `serverUrl` is the url of the server where your project lives e.g. `https://<project-id>.triplit.io` - `autoConnect` determines whether the client should connect to the server immediately upon instantiation. If set to `false`, you can manually connect with the `client.connect` method. <Callout type="warning" emoji="⚠️"> The client connects over , so you if you are instantiating a client in code that may run in an environment where WebSockets are not available , you should set `autoConnect` to `false` or preferably to an  that indicates whether the client should connect. </Callout> The `serverUrl` can be updated with the `client.updateServerUrl` method. ## Auth options These options define how you authenticate with your client database and remote database. - `token` is a jwt that is used to identify the user to the client database and remote databases ). Providing a `token` will set the variable `$session.SESSION_USER_ID` on the database, which is used for authorization rules. - `claimsPath` is the path to the Triplit claims on the token. It should be a `.` separated string like `path.to.claims`. This should match the value set on your project in the Triplit Dashboard. - `onSessionError` is a function that is called when the client receives an error from the server about the session, which will lead to the sync connection to being terminated. Read more about refreshing a session in the . - `refreshOptions` can be used to set the `refreshHandler` and `interval` for the client. Read more about refreshing a session in the . --- description: The `Include` clause is used to specify the relations on an entity that should be included in a query. --- # Include If you have defined a  using `RelationById`, `RelationOne`, or `RelationMany`, you can include those related entities in a query. For example, the following schema defines a relation between `users` and `messages`  By default, a query on `messages` will not include the `sender` as an attribute. To include the sender, use the `Include` method in the query builder.  ## Including multiple relations If a collection has multiple relations, you can select them by chaining multiple `Include` calls.  ## Aliasing and extending relations You can extend and alias relations with the `Include` method. Given a schema with a relation from `directors` to `films`:  You can write an adhoc query that narrows down a director's films to just their top 3, building off the existing `allFilms` relation.  This is also useful for querying nested data. For example:  The extending query can use any valid query builder method, such as `Order`, `Limit`, `Where`, etc. --- description: How to define and use queries in Triplit. --- # Defining queries Data in Triplit is organized into collections, so to define a query you must first specify which collection you want to query. For example, if you want to query the `users` collection, you would write the following:  ## Using queries This query object is a builder that allows you to specify  a query. To fetch data you must use a method like  or , or if you're using a query in a frontend component, you can . --- description: The `Limit` clause is used to truncate the results of a Triplit query. --- # Limit Many times you will want to limit the number of results returned by a query. To do this, you can use the `Limit` method. For example, the following query will return the 10 most recently created users.  As a convenience, Triplit also provides a method  to fetch just the first entity of a query result. --- description: The `Order` clause is used to sort results in Triplit query based on their attributes or relations. --- import { Callout } from 'nextra-theme-docs'; # Order To order the results of a query, you can use the `Order` method. This method accepts a list of order clauses as an argument. An order clause is a tuple that takes the form ``. `direction` can be either `ASC` or `DESC`. Clauses are applied in the order they are provided. For example the following query will return all users ordered by their creation date in descending order.  Clauses can be passed to `Order` as a single clause or an array of clauses: - `.Order` - `.Order` - `.Order` You may use dot notation to order by attributes of a record.  ### Ordering with relations If you are using a schema, you can order by attributes of related entities. For example, the following schema defines a relation between `users` and `messages`  You can then order messages by the name of the sender.  <Callout type="info"> Ordering with relations is only supported for one-to-one relations, such as `RelationById` or `RelationOne`. </Callout> ### After You may use the `After` method to specify an entity to start the query from. This is useful for paginating results. You must use `Order` before using `After`. At the moment, `After` only supports a single cursor that corresponds to the first `Order` clause. --- description: The `Select` clause is used to specify which attributes to return in a Triplit query. --- # Select To specify which attributes you want to return, you can use the `Select` method. This method accepts a list of attribute names for the collection as arguments.  If the type you are selecting is a record, you may also select a specific attribute of the record by using dot notation. The result will be an object with just the selected keys.  If you do not call select on a query, all attributes are selected. ## Selecting relationships Refer to the docs on  to learn how to select relationships in a query. --- description: The `SubqueryOne` and `SubqueryMany` clauses can be used to include nested queries in a Triplit query. --- import { Callout } from 'nextra/components'; # Subqueries Subqueries can be used to add an ad-hoc query on related data to an entity.  are formalized subqueries that are defined in the schema. You can use the `SubqueryOne` and `SubqueryMany` builder methods to to add any nested query to a Triplit query at runtime, regardless of relations in the schema. For example, the following schema has two collections, `users` and `blogs`, where each blog post has an `author` attribute that references a user:  ## `SubqueryMany` To query all blogs with their associated user, you can use the `SubqueryMany` method:  The return value of the subquery stored at the `userBlogs` key in each entity will be a nested array of blog items. ## `SubqueryOne` `SubqueryOne` is like `SubqueryMany`, but will return the subquery's first match. Instead of a full nested array of results, the key where the `SubqueryOne` stores it results will either be the single result or `null`. The following query will return the text of the most recent blog item created by the user: --- description: The syncStatus clause is used to filter results in Triplit query based on if they've synced with the server. --- # syncStatus Triplit's client  is split into two areas - an outbox for unsynced updates and a cache for synced updates. Sometimes you may want to indicate that to a user that data has not yet been saved to the server. To do this, you can use the `syncStatus` option in a subscription. This method accepts a single sync state  as an argument. For example, a messaging app could use two queries to build message sent indicators. In : --- description: Variables in Triplit allow you to pass in preset values into queries. --- # Variables Variables in Triplit allow you to pass in preset values into queries. They consist of a scope  and a dot  separated path to reference data in the variable. ### Query variables Query variables are prefixed with the `query` scope and are accessible just to the query they are defined on. They are defined with the `Vars` method in the query builder. For example:  This can help prevent writing the same query multiple times with different values. ### Global variables Global variables are prefixed with the `global` scope and are accessible to all queries in the database. They are defined in the client constructor or via the `updateGlobalVariables` method. For example:  ### Session variables Session variables are prefixed with the `session` scope and are accessible to all queries in that database session. When  with a Triplit server, the server will assign all claims on the JWT to session variables. ### Role variables When determining access control rules with , you can use role variables to reference values from a client's token in your permission definitions. Role variables are prefixed with the `role` scope. --- description: The `Where` clause is used to filter results in a Triplit query based on conditions. --- import { Callout } from 'nextra/components'; # Where To filter results based on conditions, you can use the `Where` method. This method accepts a list of clauses as arguments. A clause is a tuple that takes the form ``. For example the following query will return all registered users.  Clauses can be passed to `Where` as a single clause or an array of clauses: - `.Where` - `.Where` - `.Where` If multiple clauses are provided, all clauses are joined with a logical AND. However, you may use `or` and `and` methods within the clause array to specify how clauses should be logically grouped and joined. For example the following query will return all registered users who are either an admin or an owner.  You may use dot notation to filter by attributes of a record.  If you define relationships in your schema you may also access those via dot notation. Triplit will autocomplete up to 3 levels of depth, but arbitrary depth is supported.  ### Boolean clauses You may also pass in a boolean value as a clause. These statements are particularly useful when defining .  ### Exists filters You may also define a filter to check if related data exists. Triplit provides an `exists` method to help build subqueries that reference your schema.  <Callout type="warning" emoji="⚠️"> You may be tempted to write the query above as: `.Where.Where`. However, this will instead query for todos where at least one assignee is on the engineering team and where at least one assignee has the title of manager. </Callout> ### Operators See the list of  for more information on the operators that can be used in a where clause. ## Id shorthand If you want to query by the entity's ID, you can use the `Id` method as a shorthand for `Where`. E.g. --- description: Learn how to use the Sessions API for the Triplit client to model auth events in your app. --- import { Callout } from 'nextra-theme-docs'; # Sessions Triplit models connections with the server as sessions. Sessions are created when the client is initialized with a `token`, or by calling `startSession`. They end when `endSession` is called. When using durable storage like IndexedDB, they persist through page reloads, and when the client loses connection to the server. This ensures that the server sends only the changes that the client missed while it was disconnected. Triplit client sessions are easy to map to user authentication sessions, but they don't have to. They can also represent different states of the client, like a session for a guest user and a session for a logged-in user. ## `startSession` You have two options to start a session: when you initialize the client or by calling `startSession`. You usually want to initialize your client as early as possible in the lifecycle of your app, which may be before you have a token. In this case, you can create a Triplit Client without a token and then later call `startSession` when you have one.  or  You can can also decide whether or not the client should `autoConnect` to the server when you start a session. If you set `autoConnect` to `false`, you can manually connect with the `client.connect` method.  ### Refreshing a session Most authentication providers issue tokens that expire after a certain amount of time. Triplit servers will close the connection with a client when they detect that its token has expired. To prevent this, and keep the connection open, you can provide a `refreshHandler` to the client. The `refreshHandler` is a function that returns a new token, or `null`. The client will call this function 1 second before the token expires, as determined from the `exp` claim.  You can also provide an `interval` to the `refreshOptions` to set the time in milliseconds that the client will wait before calling the `refreshHandler` again. You should do this if you know the token's expiration time and want more control over when it gets refreshed.  If you want even more granular control over when the client refreshes the token, you can call `updateSessionToken` with a new token.  <Callout> It's important that tokens used to refresh a session have the same roles as the original token. They are intended to represent that same user, with the same permissions, as interpreted by roles assigned it by the server and its schema. Read more on roles . If you attempt to update the token with a token that has different roles, the server will close the connection and send a `ROLES_MISMATCH` error. </Callout> ## `endSession` When a user logs out, you should end the session. This will close the connection to the server, cleanup any refresh events, and clear some metadata about the session.  <Callout> Calling `endSession` **will not** clear the the client's database. If you want to clear the cache, you should call `client.clear`. </Callout> ## `onSessionError` `onSessionError` is a function that is called when the client receives an error from the server about the session, which will lead to the sync connection to being terminated. This can be used to end the session, restart it, and/or clear the cache. Potential error cases include: - `UNAUTHORIZED`: the token can't be verified, either because it is expired, is signed with the wrong key, or otherwise unable to be parsed. This indicates that the client has been given an erroneous token or, if you're certain that the token is valid, that the server is misconfigured. - `SCHEMA_MISMATCH`: the schema of the client and the server are out of sync. - `TOKEN_EXPIRED`: the previously valid token that had been used to authenticate the client has expired and the client will no longer receive messages. This message is sent not at the exact time that the token expires, but when the client attempts to send a message to the server or vice versa and the server detects that the token has expired. - `ROLES_MISMATCH`: occurs when the client attempts to update the token with the `refreshHandler` option for `startSession` or when using `updateSessionToken`. This error is sent when the client attempts to update the token with a token that has different roles than the previous token. This is a security feature to prevent a user from changing their privileges by updating their token with one that has different roles. --- description: Learn the different data storage options available for the Triplit client. --- # Storage Each client has the option for how they would like to store their data. ## Memory If you would only like to store data ephemerally, you can use the memory storage engine. This will store your data in memory and will not persist across page refreshes. If you use memory storage, data may be lost if the user refreshes the page before the data is sent to the server. If no storage options are provided this is the default.  ## IndexedDB If you would like to persist data between refreshes in the browser you can use the IndexedDB storage engine. This will store your data in the browser's IndexedDB database.  Note that passing `{ storage: 'indexeddb' }` to the constructor will create an IndexedDB databases with the default name `triplit`. If your application connects to multiple projects with separate clients, we recommend you create your own custom-named instances of `IndexedDBStorage` so that naming conflicts do not occur. You can inspect the IndexedDB database in the . ## Sqlite ### In the browser Triplit does not currently provide a Sqlite storage adapter for the browser. The Triplit server, which runs in node environments, can use the `sqlite` storage engine. ### In React Native Triplit provides an `expo-sqlite` storage adapter for React Native applications. This adapter uses the  package to store data on the device. Users of Expo 51 or greater can get started by importing the storage provider from `@triplit/db/storage/expo-sqlite`:  You may also instantiate the storage provider with an existing database instance:  ## Clearing your database To clear a `TriplitClient`'s database, you can call the `clear` method. The clear takes an optional parameter `full` which if set to `true` will clear the entire database including all schema and metadata. If `full` is set to `false` or not provided, only your application data will be cleared. Clearing this data will not sync, so it is useful if you need to purge the data on your client.  If you are clearing your cache because a user is signing out, it is recommended to use this in conjuction with `client.endSession` as explained in the . --- description: How to subscribe to queries in the background using subscribeBackground. --- # subscribeBackground There are certain situations in which you may want to subscribe to a query from the server without immediately needing the results. `subscribeBackground` cuts down on some of the work that `subscribe` does, by setting up a connection for a given query but not materializing the results for a callback function. The data will still be synced to the local database and accessible via other subscriptions. `subscribeBackground` can support a pattern where you have one large subscription to keep your local database up to date, and then define many local-only subscriptions that you know to be a subset of the larger subscription. This will cut down on traffic to the server and in some cases improve performance. However, it may also lead to more data being synced than is necessary. --- description: How to use the TriplitClient subscribeWithExpand method to fetch a growing window of data. --- # subscribeWithExpand `subscribeWithExpand` is a special type of subscription that is used to fetch a window of data that can programmatically grow in size. It is similar to `subscribe` but it has a few differences: - It expects the query to have an initial `Limit` defined. - It returns a `loadMore` function to fetch more data. By default, it fetches the next page of data based on the initial `limit` defined in the query. --- description: How to use the TriplitClient subscribeWithPagination method to subscribe to paginated data. --- # subscribeWithPagination `subscribeWithPagination` is a special type of subscription that is used to fetch data in pages. It is similar to `subscribe` but it has a few differences: - It expects the query to have a `Limit` defined. - It returns `nextPage` and `prevPage` functions to fetch the next and previous pages of data. - The subscription callback will have `hasNextPage` and `hasPreviousPage` booleans to indicate if there are more pages to fetch. --- description: How to use the TriplitClient subscribe method to listen to changes in your data. --- # subscribe Query subscriptions are the "live" version of a fetch. Subscribing to a query will provide continual updates to the query result based on the state of your local database. If the sync engine is connected to the remote database, subscribing to a query will keep your local database in sync with the remote database as well depending on the options provided to the subscription. Starting a subscription is as simple as defining a query and a callback to run when data has updated:  If a subscription query fails on the server then syncing for that query will stop. However, the subscription will remain active and updates to the local database will still be available. As well, the syncing of other queries will not be impacted. Although you will not receive updates from the server, updates that you make via  will be sent. ## Subscription options - `syncStatus`: Describes the set of data from the client's various sources to include in the subscription. Can be `pending`, `confirmed`, or `all`. By default, `syncStatus` is set to `all`. - `localOnly`: If set to `true`, the subscription will only listen to changes in the local database and will not attempt to sync with the remote database. Multiple small `localOnly` subscriptions are often paired with a large . By default, `localOnly` is set to `false`. - `onRemoteFulfilled`: A callback that is called when the server has first sent back results for the subscription. --- description: How to connect, disconnect, handle errors and check the connection status of the Triplit sync engine. --- # Sync Engine ## Connecting and disconnecting Instantiating a client will automatically connect to the server. If the connection is unexpectedly lost, the client will automatically reconnect. You may also manually manage the state connection to the server by calling `client.connect` and `client.disconnect`. The connection parameters used in the client constructor can be updated by using the Sessions API. Read more about it in the  ## Connection status The connection status is available at `client.connectionStatus`. You may also listen to changes in the connection status by adding a listener to `client.onConnectionStatusChange`. If the optional parameter `runImmediately` is set to `true`, the callback will be run immediately with the current connection status.  ## Handling errors Read the  documentation for more information on how to handle errors over sync. --- description: How to use the TriplitClient transact method to update a Triplit database atomically. --- # transact Transactions are a way to group multiple mutations into a single atomic operation. If any part of the mutations fail **on the client**, the entire transaction is rolled back. If the transaction succeeds on the client but fails on the server, it will need to be handled. Read the  documentation for more information on how to handle these cases. A transaction can be created by calling `client.transact`. For example: --- description: How to use the TriplitClient update method to mutate data. --- # update `update` updates an existing record in a collection. For example:  If possible, `update` will look at the schema you have provided to provide proper type hints for interacting with you data. If no schema is provided, all fields are treated as `any`. See  for more information on data types. # Web Worker Client Triplit supports running the client in a Web Worker , which can connect to multiple tabs running a script from the same domain). While running a Web Worker, data syncs between browser tabs without having to sync with server. This reduces network traffic for Triplit apps running in the multiple tabs, move Triplit local database computation to a separate thread, and allow for robust multi-tab offline support. ## `WorkerClient` The `WorkerClient` is a drop-in replacement for the `TriplitClient` that runs in a Web Worker. It provides the same API as the `TriplitClient`. To use it, import `WorkerClient` from `@triplit/client/worker-client` and create a new instance of the client:  ### With Vite To use it in , you need to import an additional parameter `workerUrl`, which helps the Vite build process to correctly bundle the Web Worker:  **However**, some frameworks, including , use Vite for development but use platform specific plugins that bundle differently for production. If you encounter issues with the `WorkerClient` in production, try removing the `workerUrl` parameter. Here's an example of how to use the `WorkerClient` in SvelteKit when deploying to Vercel that works in both development and production:  ## Debugging a `WorkerClient` Because the `WorkerClient` runs in a Shared Worker you can't immediately view the Triplit-specific logs it produces. Instead, navigate to `chrome://inspect/#workers` to view the logs for the Shared Worker. We plan to add better debugging support for the `WorkerClient` in the future. --- description: Frequently asked questions about Triplit. --- # Frequently asked questions ## Why should I choose Triplit over a traditional database? Triplit is designed to have the best developer experience possible right out of the box. It was created to make building apps with real-time, local-first user experiences much easier than with existing tools. So if you aspire to have your app to feel native while supporting collaborative features expected of modern web apps, then Triplit is probably the right choice for you. ## Why should I care about offline support? By adding offline support to your app, you end up making it fast in _all_ network conditions. Even if your users are on fast internet and you've fully optimized your server, you can't beat the speed of light. Having a robust cache on device will just improve your user experience by making each interaction feel instant and not delayed by a roundtrip to the server. This is same strategy employed by some of the most loved apps like Linear, Figma, and Superhuman. ## How can Triplit be a relational database if it doesn't use joins? In Triplit, relationships are simply sub-queries. They allow you to connect entities across collections  with the expressiveness of a query. Triplit's support for set attributes allows it to establish complex relations without join tables. Sets can be used to "embed" the related ids directly on the entity. For example, a schema for a chat app with users and messages could be defined as follows:  Check out  to learn more. ## How does Triplit handle multiple writers / collaboration / multiplayer? Every entity inserted into Triplit is broken down at the attribute level, and each attribute is assigned a unique timestamp. This means when multiple users change different attributes of the same entity, they don't conflict or collide. When two users do update the same attribute at the same time, we use these timestamps to decide which value will be kept. In the literature this type of data structure is called a CRDT or more specifically a Last Writer Wins Register that uses Lamport timestamps. A  is a Conflict-Free Replicated Data Type. It's a name for a family of data structures that can handle updates from multiple independent writers and converge to a consistent, usable state. ## Does Triplit support partial replication? Yes. We believe that partial replication is the only practical way to make applications fast over the network. When Triplit clients subscribe to specific queries the Triplit servers only send data to the clients that are listening for it and that have not yet received it. Triplit's sync protocol sends only 'deltas' between the client and server to minimize latency and network traffic. ## How do I connect to Triplit from a server? You can use the  to query and update data from a server, serverless function, command line interface, or anywhere that supports HTTP. You can also interface with the  directly. ## Why does Triplit support sets but not arrays? Every data structure that Triplit can store is designed to support multiple concurrent writers. Sets are able to handle concurrent additions and removals without problem, but arrays lose many nice properties under collaboration. Consider the push method: if two people concurrently push to an array they will end up adding an element to the same index, ultimately causing one item to overwrite the other. In the future, Triplit will expose a List datatype that will support pushing to the beginning and end of a list and assignment operations to specific indices. In most cases using a Set or a List in place of an Array will suffice. ## Why do ordinary databases struggle with collaborative applications? Many popular databases do not implement real-time query subscriptions, which are the foundation for collaborative apps. Developers generally end up replicating the functionality of their remote database on the client to create the illusion of live updating queries. --- description: Learn how use Angular bindings for the Triplit client in your app. --- import { Tabs, Tab, Callout } from 'nextra-theme-docs'; import CreateTriplitAppTabs from '../../components/CreateTriplitAppTabs.mdx'; # Angular ## New projects The fast way to get started with Triplit is to use Create Triplit App which will scaffold a Angular application with Triplit. Choose `Angular` when prompted for the frontend framework. <CreateTriplitAppTabs /> ## Existing projects If have an existing Angular project, you install the hooks provided by `@triplit/angular`: <Tabs items={}> <Tab>  </Tab> <Tab>  </Tab> <Tab>  </Tab> <Tab>  </Tab> </Tabs> ## Observables ### createQuery The `createQuery` hook return an object with observable properties that contain the results of the query, fetching states and error states.  ### createInfiniteQuery The `createInfiniteQuery` hook is similar to `createQuery`, but it is used for expanding queries, that is, queries that start with an initial limit but grow beyond that. It returns an object with observable properties that contain the results of the query, fetching states and error states, if there are more available results, and a function to load more data. It's important to define a `limit` in the query to enable the initial pagination.  ### createPaginatedQuery The `createPaginatedQuery` hook is similar to `createQuery`, but it is used for paginated queries. It returns an object with observable properties that contain the results of the query, fetching states and error states, and functions to load the previous and next pages of data. It's important to define a `limit` in the query to enable pagination.  ### createConnectionStatus The `createConnectionStatus` function returns an observable that emits the current connection status of the client. --- description: Learn how configure React Native with Expo to use Triplit in your mobile app. --- import { Tabs, Tab, Callout } from 'nextra-theme-docs'; # React Native React Native is the best way to run Triplit on a mobile app. The hooks available in the  are also available in React Native. ## Expo If you are using Expo to setup your React Native project, you can follow these steps to get Triplit up and running. ### 1. Create an Expo project and install Triplit Create your expo project:  For more information on setting up an Expo project with typescript see the . Next, install Triplit's packages: <Tabs items={}> <Tab>  </Tab> <Tab>  </Tab> <Tab>  </Tab> <Tab>  </Tab> </Tabs> ### 2. Update metro.config.js Triplit has a few packages that use features unsupported by the Metro bundler like . Triplit provides a utility for generating a custom Metro config that will resolve these exports. To handle Triplit's packages you will need to customize the Metro bundler. If you have not already created a `metro.config.js` file, please see the Expo docs on properly . Once you have created a `metro.config.js` file, you can add the following code to properly resolve Triplit packages:  If you would like more control over dependency resolution, you can import `triplitMetroResolveRequest` and use it inside a custom resolver.  ### 3. Configure Babel  If you are building for the web, you'll need to update a babel configuration file. At the root of your Expo project, create a `babel.config.js` file with the following content:  ### 4. Configure polyfills Triplit was originally built to run in web browsers, so a few APIs are used in some core packages and dependencies that are not in the ECMAScript spec that Hermes implements. So you will need to add some polyfills to your project. These polyfills should be imported or implemented in your project's entry file so they can be run as early as possible. Typically this is your `index.js` file. If you are using Expo Router see this  on creating and using an `index.js` file to add polyfills.  ### Local development When running a local development server on your machine, it will be running at `localhost`. However if you are running your app on a physical device  you will need to change the `localhost` to your machine's IP address. You can find your IP address by running `ipconfig getifaddr en0` in your terminal. So a URL `http://localhost:<port>` would become `http://<your-ip>:<port>`. ## Storage providers Triplit provides storage providers for React Native applications to persist data on the device, including for `expo-sqlite`. Read more about the available storage providers in the . ## Bare React Native The team over at Triplit hasn't had the chance to test out a bare React Native project. Although we don't expect the required steps to be much different than with Expo, there may be differences. If you have set up Triplit in a bare RN project, please let us know how it went! --- description: Learn how use React bindings for the Triplit client in your app. --- import { Tabs, Tab, Callout } from 'nextra-theme-docs'; import CreateTriplitAppTabs from '../../components/CreateTriplitAppTabs.mdx'; # React ### New projects The fast way to get started with Triplit is to use Create Triplit App which will scaffold a React application with Triplit. Choose `React` when prompted for the frontend framework. <CreateTriplitAppTabs /> ### Existing projects If you have an existing React project, you can install the hooks provided by `@triplit/react`: <Tabs items={}> <Tab>  </Tab> <Tab>  </Tab> <Tab>  </Tab> <Tab>  </Tab> </Tabs> ## useQuery The `useQuery` hook subscribes to the provided query inside your React component and will automatically unsubscribe from the query when the component unmounts. The result of the hook is an object with the following properties: - `results`: An array of entities that satisfy the query. - `fetching`: A boolean that will be `true` initially, and then turn `false` when either the local fetch returns cached results or if there were no cached results and the remote fetch has completed. - `fetchingLocal`: A boolean indicating whether the query is currently fetching from the local cache. - `fetchingRemote`: A boolean indicating whether the query is currently fetching from the server. - `error`: An error object if the query failed to fetch.  <Callout> If you're looking for the most multi-purpose loading state, `fetching` is the one to use. If you want to ensure that you're only showing the most up-to-date data from the server, you can use `fetchingRemote`. If your app is offline and should only wait for the cache, use `fetchingLocal`. </Callout> ## useQueryOne The `useQueryOne` hook subscribes to a single entity that matches the provided query. You can use this hook inside your React component and it will automatically unsubscribe from updates to the entity when the component unmounts. The result of the hook is the same as the result of `useQuery`, but the `result` property will only have a single the entity or null.  ## usePaginatedQuery The `usePaginatedQuery` hook subscribes to the provided query, and exposes helper functions to load the next or previous page of results. It is useful for patterns that load data in pages, such as paginated lists or content browsing applications.  For `usePaginatedQuery` to function properly the provided query must have a `limit` set. ## useInfiniteQuery The `useInfiniteQuery` hook subscribes to the provided query, and exposes helper functions for loading more results. It is useful for patterns that continuously load more data in addition to the existing result set. Chat applications or content browsing applications that load more data as the user scrolls are good use cases for `useInfiniteQuery`.  For `useInfiniteQuery` to function properly the provided query must have a `limit` set. By default `loadMore` will increase the limit by the initial limit set in the query. You can also provide a argument to `loadMore` denoting if you want to increment the limit by a different amount. ## useConnectionStatus The `useConnectionStatus` hook subscribes to changes to the connection status of the client and will automatically unsubscribe when the component unmounts. --- description: Learn how use Svelte bindings for the Triplit client in your app. --- import { Tabs, Tab, Callout } from 'nextra-theme-docs'; import CreateTriplitAppTabs from '../../components/CreateTriplitAppTabs.mdx'; # Svelte <Callout emoji="👉"> In anticipation of the release of Svelte 5, Triplit's Svelte bindings use . You must be using one of the pre-release versions of Svelte 5. You can force the compiler into "runes mode" . </Callout> ### New projects The fast way to get started with Triplit is to use Create Triplit App which will scaffold a SvelteKit application with Triplit. Choose `Svelte` when prompted for the frontend framework. <CreateTriplitAppTabs /> ### Existing projects If you have an existing Svelte or Svelte project, you can add the hooks provided by `@triplit/svelte`: <Tabs items={}> <Tab>  </Tab> <Tab>  </Tab> <Tab>  </Tab> <Tab>  </Tab> </Tabs> ## SvelteKit If you are using SvelteKit, you can use the hooks described below, but you will need to ensure that the client only attempts to connect to the sync server over WebSockets when in the browser. You can do this by checking if the `browser` variable from `$app/environment` is `true`.  The suggested pattern is to create a client instance in a module and import it into your components. ### `vite.config.ts` With the default SvelteKit configuration Vite will not be able to bundle files outside of the `src` or `node_modules` directory. To allow Vite to bundle the files in the `triplit` directory created with `triplit init`, you can add the following configuration to your `vite.config.ts` file:  ## useQuery The `useQuery` hook subscribes to the provided query inside your Svelte component and will automatically unsubscribe from the query when the component unmounts. The result of the hook is an object with the following properties: - `results`: An array of entities that satisfy the query. - `fetching`: A boolean that will be `true` initially, and then turn `false` when either the local fetch returns cached results or if there were no cached results and the remote fetch has completed. - `fetchingLocal`: A boolean indicating whether the query is currently fetching from the local cache. - `fetchingRemote`: A boolean indicating whether the query is currently fetching from the server. - `error`: An error object if the query failed to fetch.  ## useConnectionStatus The `useConnectionStatus` hook subscribes to changes to the connection status of the client and will automatically unsubscribe when the component unmounts. --- description: Learn how to use Tanstack Router integration with Triplit. --- import { Tabs, Tab, Callout } from 'nextra-theme-docs'; # Tanstack Router ### Introduction The `@triplit/tanstack` package provides seamless integration between Tanstack Router and Triplit, allowing you to use a Triplit query as the loader for a route which will automatically be subscribed to and update to both changes from the server as well as optimistic updates from the client. ### Installation To get started make sure you have  then install the `@triplit/tanstack` package: <Tabs items={}> <Tab>  </Tab> <Tab>  </Tab> <Tab>  </Tab> <Tab>  </Tab> </Tabs> ## `triplitRoute` The `triplitRoute` function is an integration between Tanstack Router and the Triplit client. It helps define a route with data fetched from the Triplit client and a component to render based on the fetched data.  ### Parameters - **`triplitClient`**: The instance of the Triplit client, which is used to query the data from the Triplit API. - **`query`**: A Client Query or function that returns a query to be run using the `triplitClient`. The function receives an object containing the `params` for the route. - **`Component`**: A React component that renders the data fetched by the `triplitClient`. The component receives the following props: - `results`: An array containing the results of the query - `error`: An error if the query's subscription has an error ### Returns `triplitRoute` returns a route configuration object, which can be passed to Tanstack Router's route creation functions such as `createFileRoute`. ### Example Usage Here’s an example of how to use the `triplitRoute` function with the Tanstack Router to define a route for displaying contact details:  ### Extending the Route The `triplitRoute` funciton can be extended and overriden with additional Tanstack configuration options by spreading the returned route configuration object. --- description: Learn how use Vue bindings for the Triplit client in your app. --- import { Tabs, Tab, Callout } from 'nextra-theme-docs'; import CreateTriplitAppTabs from '../../components/CreateTriplitAppTabs.mdx'; # Vue ### New projects The fast way to get started with Triplit is to use Create Triplit App which will scaffold a Vue application with Triplit. Choose `Vue` when prompted for the frontend framework. <CreateTriplitAppTabs /> ### Existing projects If have an existing Vue project, you install the hooks provided by `@triplit/vue`: <Tabs items={}> <Tab>  </Tab> <Tab>  </Tab> <Tab>  </Tab> <Tab>  </Tab> </Tabs> ## useQuery The `useQuery` hook subscribes to the provided query inside your Vue component and will automatically unsubscribe from the query when the component unmounts. The result of the hook is a  object with the following properties: - `results`: An array of entities that satisfy the query. - `fetching`: A boolean that will be `true` initially, and then turn `false` when either the local fetch returns cached results or if there were no cached results and the remote fetch has completed. - `fetchingLocal`: A boolean indicating whether the query is currently fetching from the local cache. - `fetchingRemote`: A boolean indicating whether the query is currently fetching from the server. - `error`: An error object if the query failed to fetch. Because `useQuery` uses the `reactive` function from Vue, it can't be destructured in the `setup` block. Instead, you can access the properties directly from the returned object.  ## useConnectionStatus The `useConnectionStatus` hook subscribes to changes to the connection status of the client and will automatically unsubscribe when the component unmounts. --- description: Learn how to interact with a Triplit sync server over HTTP. --- # HTTP API ## Overview The HTTP API is a RESTful API that allows you to interact with a Triplit Cloud production server or the Triplit  that you can host yourself. It's useful if your client can't connect over WebSockets, or if your application wants to forgo the local cache and optimistic updates that the Triplit sync protocol provides. This can be useful for applications that need certainty about the state of the database, or for migrating data to Triplit from other services. ## Authentication The HTTP API, like the Triplit sync protocol, uses   for authentication. If you're communicating with a Triplit Cloud production server, you'll need to use your project's Service or Anonymous Token from the  for your project. If you're communicating with a Node server that you control, you'll need a properly formed JWT with the correct claims. Using the  and `triplit dev` command will automatically generate acceptable Service and Anonymous tokens for you. With your token in hand, set up your HTTP client to send the token in the `Authorization` header with the `Bearer` scheme. Using the `Fetch` API, it would look like this:  ## `TriplitClient.http` and `HttpClient` Triplit provides helpful abstractions for interacting with the HTTP API. Read more about it in the . ## Routes ### `/fetch` Performs a fetch, returning the an array of entities that meet the query criteria.  ### `/insert` Inserts a single entity for a given collection.  ### `/bulk-insert` Inserts several entities at once that are provided as an object where the collection names are the keys and the list of entities for that collection are the values.  ### `/update` Updates a single entity for a given collection with a set of provided patches.  ### `/delete` Deletes a single entity for a given collection.  ### `/delete-all` Deletes all entities for a given collection.  ### `/healthcheck` This endpoint is publicly available  and will return a 200 status code if the server is running and healthy. --- description: Learn Triplit's different features and why you should use it in your application. --- # Welcome to Triplit <iframe style={{ marginTop: '2rem', marginBottom: '2rem' }} src={'https://www.youtube.com/embed/Aw1JB-5bHbY?mute=1'} id="ytplayer" width={512} height={310} allowFullScreen /> ### Triplit is an open-source database that syncs data between server and browser in real-time: 🔄 **Real-time sync** with incremental updates and conflict resolution at the property level <br /> 🏠 **Local caching** powered by a full-fledged client-side database <br /> 💽 **Durable server-side storage** with an admin dashboard <br /> 😃 **Optimistic updates** to make every interaction feel fast <br /> 🔗 **Relational querying** for complex data models <br /> 🛫 **Offline-mode** with automatic reconnection and consistency guarantees <br /> 🔙 **Rollback and retry management** on failed updates <br /> 🗂️ **Schemas** for data safety and Typescript autocompletion <br /> 🔐 **Authorization** with row level granularity <br /> 🤝 **Collaboration/Multiplayer** powered by  <br /> 🏎️ **Low latency** with minimal network traffic using delta patches <br /> 📝 **Simple API** for querying and mutating data in both vanilla Javascript and frameworks like React <br /> These features are required for any application that aims to be fast, responsive, and reliable, and are especially important for real-time or collaborative features. ## Why Triplit? **Triplit is fast.** By default, every update using Triplit occurs optimistically and is saved in a local cache. **Triplit is flexible.** Triplit supports arbitrary queries over it's cache and handles query invalidation for you. Triplit's cache also ensures your app will not sacrifice UX in poor or offline network conditions. **Triplit is connected.** Triplit's syncing engine handles the complexity of propagating and merging updates, making it a great fit for quickly adding real-time or collaborative features to your application. **Triplit is developer friendly.** Triplit takes care to be easy to use. It gets rid of the headaches of building a realtime system at all levels of the stack, and is potentially the only backend service you need for an app. Additionally, it is designed to work well with Typescript applications, ensuring your type definitions remain up to date as your schema evolves. **Triplit is open source.** Triplit may be self-hosted, so you can run it on your own infrastructure. Triplit also provides  - a hosted service that manages upgrades, auto-scaling, and offers technical support. The rest of the docs will explain how to use Triplit in your application. --- description: Learn how to run a local instance of the Triplit sync server for development. --- import { Callout } from 'nextra-theme-docs'; # Local Development Although you can connect directly to a managed or self hosted instance of a remote Triplit Database, you can also run a local instance of Triplit Database for development purposes. This not only helps separate your development and production environments, but Triplit's local development toolkit provides a lot of help for deploying updates to the Database. For this reason, we recommend running a local instance of Triplit Database when building most projects. ## Install the CLI If you haven't already, install the Triplit CLI and initialize a project. You can find instructions for doing so . ## Start Triplit services To start Triplit services, run the following command in your project directory:  By default this will start the following services: - Triplit Console, running at `https://console.triplit.dev/local` - Triplit Database server, running at `http://localhost:6543` And prints a usable Service Token and Anonymous Token for connecting to the database. ## Additional environment variables If your project has a `.env` file, you may set the following environment variables to configure the Triplit Database server: <Callout> If you're using a framework like  or  you should add additional environmental variables prepended with `VITE_` or `NEXT_PUBLIC_` respectively for the `DB_URL` and `ANONYMOUS_TOKEN`. For example, `TRIPLIT_DB_URL` would become `VITE_TRIPLIT_DB_URL` or `NEXT_PUBLIC_TRIPLIT_DB_URL`. </Callout> - `TRIPLIT_SERVICE_TOKEN` - The Service Token to use for connecting to the database for CLI commands. If not set, you may use a flag in the CLI  or the CLI will prompt you for a key. - `TRIPLIT_DB_URL` - The URL to use for connecting to the database. If not set, you may use a flag in the CLI  or use the default URL for the local database. - `TRIPLIT_JWT_SECRET` - Overrides the JWT secret used when generating local api tokens. - `TRIPLIT_EXTERNAL_JWT_SECRET` - Overrides the JWT secret used when generating external api tokens. - `TRIPLIT_CLAIMS_PATH` - A `.` separated path to read Triplit claims on external api tokens. If not set, claims are assumed to be at the root of the token. --- description: No extra configuration is needed for a Triplit app to work offline. --- # Offline mode Apps that use Triplit work offline by default. No extra configuration is needed. All Triplit clients save data to a local cache and mutate that cache optimistically without waiting for the server to respond. Mutations that are made offline queue in an "outbox" and are sent to the server when the client comes back online. Triplit's CRDT-based sync protocol ensures that data is eventually consistent across all clients, even those that have been offline for an extended period. ## Storage By default, Triplit clients use memory storage for the local cache. While offline, an app using memory storage will make optimistic reads and writes, and be fully functional. However, when the page is refreshed is closed or refreshed, data saved in memory storage is lost, as are any pending changes in the client's outbox. To persist data across sessions, including the outbox, you can use the .  Now not only will a user's cache be persisted across app loads, leading to faster startup times, but if users make offline changes and then close the tab, their changes will be saved and sent to the server whenever they next use the app in a connected state. ## Syncing ### Partial replication Triplit clients uses a partial replication strategy to sync data with the server. This leads to faster load times, a small storage footprint in the browser, and less data transferred over the network. Triplit clients will request the latest data from the server only for the those queries that they are  and have . When the server has new data to share, it will send only the attribute-level changes that the client has not yet seen. ### Connected states Triplit clients expose their current connection status with `connectionStatus` and `onConnectionStatusChange` properties, or in a given framework using the appropriate hook  in `@triplit/react`). These can be used to render UI elements that indicate whether the client is online or offline. The Triplit client also exposes methods `connect` and `disconnect` that can be used to manually control the client's connection status. ## Local-only mode If you want to use Triplit without syncing data to a server, you can set the  option to `false` or omit the `serverUrl` and `token` options when creating a client. In this mode, the client will still save data to a local cache and make optimistic updates, and no data will be sent to the server. If you are using a form of durable storage, such as `indexeddb`, data will persist across app loads, and can eventually be synced to a server in a later iteration of your app. --- description: Learn how to get up and running with a simple Triplit app. --- import { Callout, Tabs, Tab, Steps, Collapse, FileTree, } from 'nextra-theme-docs'; import CreateTriplitAppTabs from '../components/CreateTriplitAppTabs.mdx'; # Quick Start <Steps> ### Install Triplit to your app #### New projects The fast way to get started with Triplit is to use Create Triplit App which will scaffold a full stack application with Triplit. <CreateTriplitAppTabs /> #### Existing projects If you have an existing project, you can install the `triplit init` command to create the necessary files and folders and install the required dependencies. <Tabs items={}> <Tab>  </Tab> <Tab>  </Tab> <Tab>  </Tab> <Tab>  </Tab> </Tabs> Follow the instructions in the  to finish your setup. The tutorial uses React but is applicable to any framework. ### Create your Schema <FileTree> <FileTree.Folder name="triplit" defaultOpen> <FileTree.File name="schema.ts" /> </FileTree.Folder> </FileTree> You'll find a schema already setup in your project. You can modify this file to define the collections in your database. To learn more about schemas, check out the . ### Configure your client <FileTree> <FileTree.Folder name="triplit" defaultOpen> <FileTree.File name="client.ts" /> </FileTree.Folder> </FileTree> To sync with a Triplit server, your frontend needs a `TriplitClient`. Create a `client.ts` file in your `triplit` folder and export a client.  This snippet is configured to connect with a default local development server. Once you've deployed your own server or are using Triplit Cloud, you'll need to update the `serverUrl` and `token` fields and store them as environmental variables. ### Setup your dev server Triplit has a robust local development environment that you can set up with a single command.  The `dev` command will start a local Triplit server with your schema applied. To learn more about the dev server, check out the . ### Insert and Query Data To add data to your database you can use the pre-configured client to  data.  To run a query and subscribe to changes to that query, you can use .  There also framework specific bindings for  and  that you can use to interact with your data. ### Deploy When you're ready to go live, you'll need Triplit Server running. Check out the other guides to learn how you can  or . With your server running and your `.env` setup, you can now push your schema to the server  That's it! But there's a lot more you can do with Triplit. Check out the rest of the docs to learn more about how to define , , add , and more. </Steps> --- description: A full tutorial for building a Todos app with React, Vite and Triplit. --- import { Callout } from 'nextra/components'; <Callout emoji="💡"> If you're not interested in building the app from scratch, you can get a fully working demo app by running `npm create triplit-app@latest`. </Callout> # Build a Todos app with React, Vite and Triplit This tutorial will show you how to build a simple Todos app with React, Vite and Triplit. It will cover the following topics: - How to create a new Triplit project - How to create a new React app with Vite - How to create a Triplit schema for the Todos app - How to use the Triplit console - How to read and mutate data with Triplit - How to sync data with Triplit The app will be built with: -  as the UI framework -  as the build tool -  as the database and sync engine If at any time you want to check your progress against the finished app, or if you get stuck, you can find the source code for the finished app . ## Project setup ### Create a new project Let's use Vite to create a new React app. Run the following command in your terminal:  Follow the prompts to create a new project. Once it's been created, navigate to the project directory:  ### Add in Triplit Before we start building the app, we need to integrate Triplit and its dependencies project. You can do this by installing the , the , and running the `init` command.  This will will create some Triplit-specific files and add the necessary dependencies. The directory structure for your new project should look like this:  ### Define the database schema Triplit uses a  to define the structure of your data. By using a schema, Triplit can validate your data at runtime and provide autocompletion in your editor. We're going to set up a  for the Todos app in the `./triplit/schema.ts` file. Open the file and replace its contents with the following code:  This schema defines a single collection, `todos`, with the following fields: - `id`: A unique identifier for the todo. Every Triplit collection must have an `id` field. Defaults to a random string if not specified. - `text`: A string that contains the todo text. - `completed`: A boolean value that indicates whether the todo is completed or not. Defaults to `false` if not specified. - `created_at`: A timestamp that indicates when the todo was created. Defaults to the current time if not specified. ### Start the development server Triplit provides a development server that you can use to test your app locally. To start the development server, run the following command:  This will start the sync server at `http://localhost:6543` and a database console at `https://console.triplit.dev/local`. It will also output API tokens that your app will use to connect to the sync server. <Callout emoji="💡"> If you're using our hosted service, Triplit Cloud, you can use the API tokens and url shown on the  for your project page. The instructions in the rest of this tutorial are the same whether you're using Triplit Cloud or running the sync server locally. </Callout> Now's a good time to set up an `.env` file in the `todos` directory. This file will contain the API tokens that your app will use to connect to the sync server. Create a new file called `.env` in the `todos` directory and add the following:  Make sure you have `.env` as part of your `.gitignore` file:  Now restart the development server by pressing `Ctrl + C` and running `npx triplit dev` again. We're basically done setting up Triplit. Now we can start building the app. <Callout emoji="💡"> The development server automatically loads your schema on startup. If you're using Triplit Cloud, run `npx triplit schema push` to make the remote server aware of the schema you've defined. </Callout> ## Building the app Let's start building the app. ### Getting started with Vite Vite is a build tool that makes building apps fast and easy. We already installed Vite above, so let's start using it. In a new terminal, in the `todos` directory, run the following command to start the Vite development server:  This will start the Vite development server on port `5173`. You can now open your browser and navigate to `http://localhost:5173` to see the app. ### The Triplit client Now that we have the development server running, let's integrate Triplit into our client code. Triplit provides a client library that you can use to read and write data. Let's initialize it with our API tokens and the schema that we defined earlier. Create a new file in the `triplit` directory called `client.ts` and add the following code:  Any time you want to read or write data, you'll import the `triplit` object from this file. ### Optional: styling The Vite app template comes with some basic styles. Feel free to replace them with your own styles or some of ours. Replace the contents of index.css with the following:  ### Creating todos The Vite app template comes with an `App.tsx` file that contains some components. Let's replace it with an `<form/>` component that creates a new todo. Replace the contents of `App.tsx` with the following:  This component renders a form with a text input and a submit button. When the form is submitted, it calls `triplit.insert` to create a new todo. It uses React to update the text input's value and clear it when the form is submitted. <Callout emoji="💡"> Notice that in the call to `triplit.insert`, we're omitting several of the fields we defined in our schema. That's because those missing fields, `id`, `completed`, and `created_at`, have default values. Triplit will automatically fill in those fields with their default values. </Callout> ### The Triplit console We have a component that creates a new todo, but we still need to write some code that fetches the todos from the database and renders them on the page. If we want to test that our insertions are working without doing any more work, we can use the Triplit console. When you ran `npx triplit dev` earlier, it started a Triplit console. This is located at `https://console.triplit.dev/local`. You should see a page that looks like this: ! The console allows you to view and edit the contents of your database. You can use it to view the todos that you've created so far. You can also use it to create new todos or update existing ones. Add some todos from your Vite app, and watch them appear in the `todos` collection in the console. Then, in the console, click on a cell in the new rows that appear and update it. <Callout emoji="💡"> The Triplit console is super powerful. Not only can you mutate data, but you can apply filters, sorts, navigate relations and more. </Callout> ### Creating a todo component Now that we have a way to create a new todo, let's create a component that renders a todo. Create a new `components` directory inside the `src` directory and a file called `Todo.tsx` and add the following code:  In this component, we're rendering a checkbox and some text describing our todo. The `Todo` component takes a single prop, a `Todo` entity, and renders it. To get the `Todo` type from our schema we use the `Entity` generic type, and pass in our schema and the name of the collection  that we want a type for. When the checkbox is clicked, we call `triplit.update` to update the todo's `completed` field. `triplit.update` takes three arguments: the name of the collection, the id of the entity to update, and a callback that updates the entity. When the ❌ button is clicked, we call `triplit.delete` to delete the todo. `triplit.delete` takes two arguments: the name of the collection and the id of the entity to delete. ### Rendering the todos Now that we have a component that renders a todo, let's render a list of todos. First, let's query the todos from the database. We're going to use the `useQuery` hook provided by Triplit to query the todos and store them as React state. At the top of `App.tsx`, add the following code:  The `useQuery` hook takes two arguments: a Triplit client and a query. The query is created by calling `triplit.query` and passing in the name of the collection that we want to query. `useQuery` returns an object with the following properties: - `results`: An `Array<Todo>` that contains the results of the query. - `error`: An error object if the query failed, or `undefined` if the query succeeded. - `fetching`: A boolean that indicates whether the query is currently fetching data. <Callout emoji="💡"> One thing to notice is that we've added an `order` clause to the query. This will order the todos by their `created_at` field in descending order. This means that the most recently created todos will be at the top of the list. Triplit's query API supports a wide range of clauses, including `where`, `limit`, `offset`, `order`, and more. You can learn more about the query API . </Callout> Now we're going to render the todos in the `App` component. Add the following lines to the `App` component:  Here we've: 1. Imported our `<Todo/>` component 2. Called the `useTodos` hook to query the todos 3. Rendered the todos by iterating over the array with `Array.map` in our `<App/>` component. <Callout emoji="💡"> Triplit queries are *live*, meaning that you never need to manually refetch data. As other clients insert, update or delete data, your query will automatically update to reflect those changes. Even if you go offline, the query will listen for the changes that you make locally and update the query with those local changes. When you go back online, the Triplit will sync those local changes with the server and pull in any changes it missed while we were offline. </Callout> ## Persisting data So far, Triplit has been storing data in-memory . That means that if you refresh the page and go offline, you'll lose your data. Triplit supports a variety of  that you can use to persist your data even between refreshes or if you go offline.  is a low level durable storage API built into all modern browsers. Update the `client.ts` file to use the `indexeddb` storage option:  When you use the Triplit client to insert or update data, that data will persist to IndexedDB. Test it out: if you create a few todos and refresh your browser, you should see that your todos are still there. ## Testing out the sync Now that we have a working app, let's test out the sync. In one browser window, navigate to `http://localhost:5173`. Then, open a private browsing window and navigate to `http://localhost:5173`. You should see the same app in both tabs. Now, create a new todo in one tab. You should see the todo appear in the other tab. Try checking and unchecking the todo. You should see the changes reflected in the other tab. Triplit works offline as well - try disconnecting from the internet and creating a new todo in one of the windows. You should see the todo appear in the other tab when you reconnect. This is the power of syncing with Triplit! ## Next steps We've built a simple Todos app with React, Vite and Triplit. We've learned how to: - Create a new Triplit project - Create a new React app with Vite - Create a Triplit schema for the Todos app - Read and mutate data with Triplit - Sync data with Triplit And there are still a lot of things that we haven't covered. - The rest of Triplit's  to select, filter and paginate data - Triplit's  to control who can read and write data - Triplit's  - Triplit's  to establish relationships between collections and then  - The various  for your Triplit client's cache If you have any questions, feel free to reach out to us on  or . --- description: Learn how use a schema in your Triplit app to enable Typescript support and data validation. --- import { Callout } from 'nextra-theme-docs'; # 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. -  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:  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  for more information. <Callout> 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. </Callout> ### 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.  ### 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.  #### `QueryResult` If you need more advanced types, e.g. that include an entity's relationships, you can use the `QueryResult` type. It allows you to generate the return type of any query, e.g. with a `Select` clause that narrows fields or `Include` clauses that add related entities.  ### 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:  See  or run `triplit schema print --help` for more options. --- description: How to manage access control rules with a Triplit schema. --- import { Callout } from 'nextra-theme-docs'; # Authorization and access control <Callout type="info"> This feature is available for all hosted  users. If you are self-hosting Triplit, this feature is available in Triplit 0.3.58 and higher. </Callout> <Callout type="warning" emoji="⚠️"> Access control checks run exclusively on the server, and are not enforced on the client. Invalid writes will only be rejected when they have been sent to the server. </Callout> Triplit provides a flexible way to define access control rules for your database, ensuring that your application data is secure without the need for complex server-side logic. ## Roles When a client authenticates with a Triplit server and begins a session, it provides a token that contains some information about itself  for more information on tokens). You can define `roles` to access information from a token to inform permissions decisions, like 'Can this user read this todo?'. Each role has an identifier and a `match` object. When a client authenticates with a Triplit server, Triplit will check if the token matches any defined roles in the schema. If it does, the client is granted that role and will be subject to any permissions that have been defined for that it. For example, you may author `admin` and `user` tokens with the following structure:  Wildcards in the `match` object  will be assigned to  with the prefix `$role`. For example, a JWT with the following structure would match the `user` role and assign the value `123` to the `$role.userId` variable for use in your application's permission definitions:  Your schema file should export the `roles` object for use in your schema definitions. ## Permissions <Callout type="warning"> Access control at the attribute level is not yet supported, but will be in a future release. </Callout> By default, there are no access controls on the database and they must be configured by adding a `permissions` definition to the schema. Each collection in a schema can have a `permissions` object that defines the access control rules for that collection. Once a permissions object is defined, Triplit will enforce the provided rules for each operation on the collection. If no rules for an operation are provided, the operation not be allowed by default. The following example turns off all access to the `todos` collection so it is only accessible with your :  Collection permissions are defined for each operation and role. If a role is not included, it will not be allowed to perform that operation. When performing each operation, Triplit will check the set of set of  that must be satisfied for the operation to be allowed.  ### Read To allow clients to read data, you must define a `read` permission that specifies the roles that may read data and any additional restrictions. The following example allows a `user` to read the todos that they authored and an `admin` to read any todo:  ### Insert To allow clients to insert data, you must define an `insert` permission that specifies the roles that may insert data and any additional restrictions. The following example allows a `user` to insert a todo that they author and an `admin` to insert any todo:  ### Update To allow users to update data, you must define an `update` permission that specifies the roles that may update data and any additional restrictions. For updates, the permission is checked against the "old" state of the entity, before it has been updated. The following example allows a `user` to update todos that they authored and an `admin` to update any todo:  ### Post update You may also optionally define a `postUpdate` permission that will be run after an update operation has been completed. This is useful for confirming that updated data is valid. For example, this checks that a `user` has not re-assigned a todo to another `user`:  ### Delete To allow users to delete data, you must define a `delete` permission that specifies the roles that may delete data and any additional restrictions. The following example allows a `user` to delete todos that they authored and an `admin` to delete any todo:  ## Editing permissions Permissions are a part of your schema and can be added or updated by . In a future release, you will be able to manage permissions in your project's . ## Modeling permissions with external authentication When using an external authentication provider like , the provider is the source of truth for identifying users. This means that in your Triplit database you might not need a traditional users collection. Permissions that restrict access to specific authenticated users should use the ids provided by the auth service. If you want to store additional information about a user in Triplit, we recommend using a `profiles` collection that uses the same ID as the user ID provided from your auth provider. When your app loads and a user authenticates, you can fetch their profile or create it if it doesn't exist. Here’s an example schema: --- description: Learn how to model relational data in a Triplit schema. --- # Relations To define a relationship between two collections, you define a subquery that describes the relationship with `RelationMany`, `RelationOne` or `RelationById`. while `RelationOne` and `RelationById` are designed for singleton relations and will be directly nested or a sub-object or `null` if an applicable entity doesn't exist. Within a relation, either in a where clause or the `RelationById` id, parameter, you can reference the current collection's attributes with `$`. ## RelationMany A `RelationMany` attribute will be in the shape `Array<Entity>`. It's designed to model a one-to-many relationship between two collections. If no related entities are found, the attribute will be an empty array. In this example schema, we are modeling a school, where departments have many classes. The `departments` collection has a `classes` attribute that is a `RelationMany` to the `classes` collection.  ## RelationOne A `RelationOne` attribute will be an `Entity` or `null`. It's designed to model a one-to-one relationship between two collections. The `RelationOne` attribute will be the related entity or `null` if no related entity is found. We can update our model of a school, so that a class has a relation to its department.  ## RelationById RelationById is a special case of `RelationOne` that is used to define a relationship by a foreign key. The `RelationById` attribute will be the related entity or `null` if no related entity is found. We can update the previous example to use `RelationById` instead of `RelationOne`.  ## Querying collections with relations By default, queries on collections with relations will _not_ return related data. You can use the `include` method to specify which relations you want to include in the query.  ## Defining relations with referential variables TODO --- 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: ### Collections and Schema types The `Collections` and `Schema` schema types are used to define your collections and their attributes. They are simple record types but will help provide type hinting and validation to their parameters.  ### Value types Value types are basic types for the database. #### String The string data type is used to store text.  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  any single character; a percent sign  matches any sequence of zero or more characters. For example:  ##### `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:  #### Number The number data type is used to store integer or float numbers.  Numbers support `=`, `!=`, `>`, `>=`, `<`, `<=`, `in`, `nin`, and `isDefined` operators in `where` statements. #### Boolean The boolean data type is used to store true or false values.  Booleans support `=`, `!=`, and `isDefined` operators in `where` statements. #### Date The date data type is used to store date and time values.  Dates support `=`, `!=`, `>`, `>=`, `<`, `<=`, and `isDefined` operators in `where` statements. #### 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 . </Callout>  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. ### 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.  #### `optional` You can indicate an attribute is optional by passing the `{ optional: true }` option to its constructor or wrapping the attribute in `S.Optional`. Optional attributes are not required for insertion by the schema and will be `undefined` at runtime if not provided. Optional attributes may also be deleted and assigned to `null` in updater functions.  Optional attributes support the `isDefined` operator, which checks if the specified attribute is defined.  #### `default` You can provide defaults values or functions for an attribute. Triplit currently support literal values and the following functions: - `uuid`  - `now`  - `Set.empty`  The below schema has literal and function default values.  #### `enum`  You can provide an array of strings to the `enum` option to restrict the possible values of a string attribute.  This will both perform runtime validation and provide autocomplete in your editor. ### Record Record types allow you model nested information. They support the `nullable` option. --- description: Learn how to update a schema for your Triplit server in production. --- import { Callout } from 'nextra-theme-docs'; # Safely updating schemas in production ## Client compatibility When a client connects to a Triplit server, it compares the schema it has stored locally with the schema on the server. If the schemas are incompatible, the client will refuse to connect to the server. This is a safety feature to prevent data corruption. That does not mean that you can't update your schema on the server, but you must do so in a way that is backwards compatible. This page describes the tools Triplit provides to make this process as smooth as possible. ## Getting setup Let start with a simple schema, defined at `./triplit/schema.ts` in your project directory.  You can start the development server with the schema pre-loaded.  By default, the server will use in-memory storage, meaning that if you shut down the server, all of your data will be lost. This can be useful when you're early in development and frequently iterating on your schema. If you like this quick feedback loop but don't want to repeatedly re-insert test data by hand, you can use Triplit's . You can use seed command on its own:  Or use the `--seed` flag with `triplit dev`:  If you want a development environment that's more constrained and closer to production, consider using the  persistent storage option for the development server:  Your database will be saved to `triplit/.data`. You can delete this folder to clear your database. ## Updating your schema Let's assume you've run some version of `triplit dev` shown above and have a server up and running with a schema. You've also  such that Triplit CLI commands will be pointing at it. Let's also assume you've added some initial todos:  ### Adding an attribute Now let's edit our schema by adding a new `tagId` attribute to `todos`, in anticipation of letting users group their todos by tag.  ### Pushing the schema We're trying to mimic production patterns as much as possible, so we're not going to restart the server to apply this change . Instead let's use a new command:  This will look at the schema defined at `./triplit/schema.ts` and attempt to apply it to the server while it's still running. In our case, it fails, and we get an error like this:  What's at issue here is that we **tried to change the shape/schema of a todo to one that no longer matches those in the database**. All attributes in Triplit are required by default, and by adding a new attribute without updating the existing todos, we would be violating the contract between the schema and the data. Thankfully, the error gives us some instructions. We can either 1. Make `tagId` optional e.g. `tagIds: S.Optional)` and permit existing todos to have a `tagId` that's `undefined`. 2. Delete all of the todos in the collection so that there isn't any conflicting data. While 2. might be acceptable in development, 1. is the obvious choice in production. In production, we would first add the attribute as optional, backfill it for existing entities with calls to `client.update`, as well as upgrade any clients to start creating new todos with `tagId` defined. Only when you're confident that all clients have been updated to handle the new schema and all existing data has been updated to reflect the target schema, should you proceed with a backwards incompatible change. Whenever you try to `triplit schema push`, the receiving database will run a diff between the current schema and the one attempting to be applied and surface issues like these. Here are all possible conflicts that may arise. ### Fixing the issues Let's make `tagId` optional:  Now we can run `triplit schema push` again, and it should succeed. For completeness, let's also backfill the `tagId` for existing todos:  We've now successfully updated our schema in a backwards compatible way. If you're confident that all clients have been updated to handle the new schema and all existing data has been updated to reflect the target schema, you can then choose to make `tagId` required. ## Handling backwards incompatible changes ### Adding an attribute where optional is not set Like in the example above, these changes will be backwards incompatible if you have existing entities in that collection. In production, only add _optional_ attributes, and backfill that attribute for existing entities. ### Removing a non-optional attribute This is a backwards incompatible change, as it would leave existing entities in the collection with a missing attribute. In production, deprecate the attribute by making it optional, delete the attribute from all existing entities , and then you be allowed to remove it from the schema. ### Removing an optional attribute While not technically a backwards incompatible change, it would lead to data loss. In production, delete the attribute from all existing entities first  and then it will be possible to remove it from the schema. ### Changing an attribute from optional to required This is a backwards incompatible change, as existing entities with this attribute set to `undefined` will violate the schema. In production, update all existing entities to have a non-null value for the attribute, and then you will be able to make it required. ### Changing the type of an attribute Triplit will prevent you from changing the type of an attribute if there are existing entities in the collection. In production, create a new optional attribute with the desired type, backfill it for existing entities, and then remove the old attribute following the procedure described above . ### Changing the type of a set's items This is similar to changing the type of an attribute, but for sets. In production, create a new optional set attribute with the desired type, backfill it for existing entities, and then remove the old set following the procedure described above . ### Changing an attribute from nullable to non-nullable Triplit will prevent you from changing an attribute from nullable to non-nullable if there are existing entities in the collection for which the attribute is `null`. In production, update all of the existing entities to have a non-null value for the attribute and take care that no clients will continue writing `null` values to the attribute. Then you will be able to make it non-nullable. ### Changing a string to an enum string or updating an enum Triplit will prevent you from changing a string to an enum string or updating an enum if there are existing entities in the collection with values that are not in the new enum. In production, update all of the existing entities to have a value that is in the new enum and then you will be able to make the change. ### Removing a relation Because relations in Triplit are just views on data in other collections, removing a relation will not corrupt data but can still lead to backward-incompatible behavior between client and server. For instance, if the server's schema is updated to remove a relation, but an out-of-date client continues to issues queries with clauses that reference that relation, such as `include`, a relational `where` filter, or an `exists` filter, the server will reject those queries. In production, you may need to deprecate clients that are still using the old relation and force them to update the app with the new schema bundled in. --- description: Learn how seed a Triplit database with the `triplit seed` command. --- # Seeding a Triplit Database In this guide, we'll walk through how to use `triplit seed` to seed a database. ## Creating a seed file First, we'll need to create a seed file. This is a file that contains the data we want to seed the database with. We'll use the `triplit seed` command to this file.  This will create a file called `my-first-seed.ts` in the `triplit/seeds` directory. It will introspect your  defined in `./triplit/schema.ts`. It will use the schema to provide some initial type hinting to help ensure that the data in your seed adheres to the schema. For example, a schema file might look like this:  And would result in a seed file that looks like this:  ## Editing the seed file Now that we have scaffolded a seed file, we can start adding data to it. Let's add a few todos:  You can add whatever scripts you want to this file, including external libraries, as long as it exports a default function that adheres to the `BulkInsert` type . ## Using the seed file Now that we have a seed file, we can use the `triplit seed run` command to seed the database. First, make sure that your environment variables are set up correctly, with `TRIPLIT_DB_URL` pointing to your database  and `TRIPLIT_SERVICE_TOKEN` set to a valid service token. Then, run the `triplit seed create` command with the name of the seed file as an argument:  You should see some output  ## `triplit seed` variants ### `create` You can use the `--create` option to create a seed file with some helpful typescript. This will introspect your schema and provide some initial type hinting to help ensure that the data in your seed adheres to the schema.  ### `--all` You can define multiple seed files in the `triplit/seeds` directory. You can run them all at once by using the `--all` option.  ### `--file` You can also run a specific seed file, not necessarily located in `triplit/seeds/.ts` by using the `--file` option. --- description: Learn how to self host Triplit using Docker, and how to deploy it to a cloud provider with Docker or Git. --- import { Callout } from 'nextra/components'; # Self-hosting Triplit To enable sync, you need to run a Triplit server. The server is a Node.js application that talks to various Triplit clients over WebSockets and HTTP. You have several options for running the server: - A local  - Use  and a cloud provider that supports container deployments - Use a  to a cloud provider that is integrated with Triplit. - Build  and use a cloud provider that supports Git-based deploys <Callout type="warning" emoji="⚠️"> The guide on this page is specifically for standalone, self-hosted deployments that are not compatible with the Triplit Cloud Dashboard. We recommend that you instead follow  for self-hosting your Triplit Server while still making it accessible and configurable via the Triplit Dashboard. </Callout> ## Docker Each release of the server is . You can deploy the server to a cloud provider like , , or AWS. You'll also want to setup a volume to persist the database. The docker file starts a node server on port 8080, and you can pass in the following environment variables to configure the server: - `NODE_OPTIONS` - Node.js options for the server  ## One-click deploy Triplit is integrated with , a cloud provider that supports one-click deploys. Read about how to deploy a Triplit server using Railway in our . We plan on adding support for more cloud providers in the future. If you have a favorite cloud provider that you'd like to see integrated with Triplit, let us know by . ## Building a custom server The server is published as an NPM package, and you can install it by running:  The server also contains the remote Triplit database, which will persist data synced from your clients. The server supports different storage adapters, such as SQLite. Using the `createServer` function, you can create and configure a new server instance:  You can now deploy the server to a cloud provider that supports Git deploys, like , , or . ### Storage Triplit is designed to support any storage that can implement a key value store. You may specify the storage adapter you want to use by setting the `storage` option. Triplit provides some default configurations of our storage adapters, which you can use by setting the `storage` option to the appropriate string value for the adapter. These include: - `memory`  - See `memory-btree` - `sqlite` - An SQLite storage adapter, which requires the installation of the  - `lmdb` - An LMDB storage adapter, which requires the installation of the  <Callout type="warning" emoji="⚠️"> In-memory storage adapters are not durable and are not recommended for production use. </Callout> Typically this will use your `LOCAL_DATABASE_URL` environment variable so you'll want to make sure that's set. You can also pass in an instance of an adapter or a function that returns an instance of an adapter.  ## Health checks The server exposes a health check endpoint at `/healthcheck`. This endpoint will return a 200 status code if the server is running and healthy. ## Secrets There are a few secrets that you need to provide to the server to enable certain features. **If you are planning on using the Triplit Dashboard, you will need to set `JWT_SECRET` to the global Triplit public RSA key associated with your project.** Read the  for more information. ### `JWT_SECRET` The server uses JWT tokens to authenticate clients, and you need to provide a symmetric secret or public key to verify these tokens that it receives. The `JWT_SECRET` environment variable should be assigned to this validation secret. Triplit supports both symmetric  and asymmetric  encryption algorithms for JWTs. You will need to generate client tokens signed with the appropriate algorithm. You can generate tokens with the `jsonwebtoken` package  :  For more complicated authentication schemes, refer to our . ### `LOCAL_DATABASE_URL`  An absolute path on the server's file system to a directory where the server will store any database files. This is required for durable storage options: `lmdb`, and `sqlite`. ### `EXTERNAL_JWT_SECRET`  <Callout type="warning" emoji="⚠️"> If you plan to connect your self-hosted Triplit server to the Triplit Dashboard and use JWTs for authentication and permission within Triplit, EXTERNAL_JWT_SECRET should only be set on your Triplit Dashboard. Ensure the env var is NOT included wherever you deployed your Docker image. Otherwise, you may encounter errors related to invalid JWTs and JWT signatures. </Callout> If you want your server to support JWTs signed by a second issuer, you can also set `EXTERNAL_JWT_SECRET` to that signing secret . For the server to recognize a JWT as "external", it must **not** have the `x-triplit-token-type` claim or if that claim is set, it must **not** have the value of `anon` or `secret`. Those specific combinations of claims are reserved for "internal" JWTs, e.g. the special `anon` and `secret` tokens. ### `CLAIMS_PATH`  If you are using custom JWTs with nested Triplit-related claims, you can set the `CLAIMS_PATH` environment variable. The server will read the claims at the path specified by `CLAIMS_PATH`. Read the  for more information. ### `SENTRY_DSN`  If you want to log errors to Sentry, you can set the `SENTRY_DSN` environment variable. The server will automatically log errors to Sentry. ### `VERBOSE_LOGS`  If you want to log all incoming and outgoing messages and requests, you can set the `VERBOSE_LOGS` environment variable. This can be useful for debugging. # Server-side rendering Triplit is designed to work in a client-side environment, but it can work in a server-side rendering  environment as well. ## The HTTP client When working with Triplit data in a server environment , the `TriplitClient`'s default query and mutation methods will not work. They rely on establishing a sync connection over `WebSockets`, which is not possible in many stateless server-rendering environments. Instead, use the , a stateless Triplit client that can perform operations on a remote Triplit server over HTTP. It is fully-typed and has a broadly similar API to the core Triplit Client.  ## Client configuration Though we recommend only using the  to _fetch or mutate data_ in a server-rendering environment, a `TriplitClient` can be instantiated in code that runs on a server with some specific configuration. You will often want to do this if you have a single `TriplitClient` instance that is shared between server and client code. ### WebSockets and auto-connect By default, a new client attempts to open up a sync connection over  with the provided `serverUrl` and `token`. This auto-connecting behavior is controlled with the `autoConnect` client parameter. If you are instantiating a client in code that may run in an environment where WebSockets are not available , you should set `autoConnect` to `false` or preferably to an  that indicates whether the client should connect. Allowing the client to attempt to connect to the server over WebSockets in a server-side rendering environment will result in an error or undefined behavior. Here's an example in SvelteKit:  ### Storage You may chose to use a storage provider like IndexedDB to provide a durable cache for your client. IndexedDB is not available in a server-side rendering environment, so you should use a different storage provider in that case. Attempting to use IndexedDB in a server-side rendering environment will result in an error or undefined behavior. Continuing the SvelteKit example:  ## Looking ahead In the future, we plan to provide a more robust solution for server-side rendering with Triplit. Keep an eye on  and  to stay updated. --- description: Learn how to create Triplit Cloud projects. --- import { Callout } from 'nextra-theme-docs'; import Image from 'next/image'; import signIn from '../../../public/dashboard-screenshots/sign-in.png'; import authentication from '../../../public/dashboard-screenshots/authentication.png'; import dataManagement from '../../../public/dashboard-screenshots/data-management.png'; import quickstart from '../../../public/dashboard-screenshots/quickstart.png'; import createProject from '../../../public/dashboard-screenshots/create-project.png'; # Triplit Cloud Triplit Cloud is a service for managing your Triplit projects. It's free for individuals to use, and integrates with your Triplit server, whether it's managed by us or self-hosted. When you integrate with Triplit Cloud you get access to a range of features, including: - **The Triplit Console**: A graphical interface for managing your data and schema. - **Authorization**: Configure access to your server without needing to modify your server's code. To get started with Triplit Cloud, read one of our guides below: -  - --- description: Learn about Triplit Cloud's managed machines. --- import { Steps } from 'nextra-theme-docs'; import Image from 'next/image'; import managedMachines from '../../../public/dashboard-screenshots/managed-machines.png'; import machineWidget from '../../../public/dashboard-screenshots/machine-widget.png'; import createProject from '../../../public/dashboard-screenshots/create-project.png'; # Managed machines Triplit Cloud offers managed machines for hosting your Triplit server. Managed machines are a great way to get started with Triplit, as they require no setup or maintenance on your part. We handle all the server management, so you can focus on building your app. <Steps> ### Create a project -  - Click the **Create Project** button - Provide a name for your project. This will act as a friendly alias for your project throughout the dashboard. <Image src={createProject} alt="Project creation page" width={'100%'} style={{ borderRadius: 16, marginTop: 32 }} /> ### Choose and deploy a machine Once you've created a project, you'll be presented with a choice of deployment options under the **Triplit Cloud** tab: <Image src={managedMachines} alt="Managed machines options" width={'100%'} style={{ borderRadius: 16, marginTop: 32 }} /> Once you've chosen a deployment machine configuration and region, click the **Deploy** button. This will bring you to a checkout page, where you can review your order and enter your payment details. ### View your machine Once your machine is deployed, you can view its status on the **Overview** tab of your project dashboard. Here you'll see information about your machine, including its region, storage and status. <Image src={machineWidget} alt="Machine widget" width={'50%'} style={{ borderRadius: 16, marginTop: 32 }} /> ### Use the dashboard You can use the Triplit dashboard to: - Mint API keys and rotate them as needed - Allow your server to accept external tokens signed with different secrets - Manage your data and schema with the  Copy the secrets from the **Overview** tab  into your app's `.env` file. ! </Steps> --- description: Learn about connecting a self-hosted server to Triplit Cloud. --- import { Steps, Callout } from 'nextra-theme-docs'; import Image from 'next/image'; import selfHosting from '../../../public/dashboard-screenshots/self-hosting.png'; import machineWidget from '../../../public/dashboard-screenshots/machine-widget.png'; import createProject from '../../../public/dashboard-screenshots/create-project.png'; # Self-hosted deployments Triplit Cloud is fully compatible with self-hosted Triplit servers. This means you can deploy your own Triplit server and connect it to the Triplit Cloud dashboard, and reap the benefits of easier server management and use of the Triplit Console. <Steps> ### Create a project -  - Click the **Create Project** button - Provide a name for your project. This will act as a friendly alias for your project throughout the dashboard. <Image src={createProject} alt="Project creation page" width={'100%'} style={{ borderRadius: 16, marginTop: 32 }} /> ### Deploy your project After creating your project, you'll be shown some information about your project, and instructions for deploying a self-hosted machine. <Image src={selfHosting} alt="Self hosting instructions" width={'100%'} style={{ borderRadius: 16, marginTop: 32 }} /> You have two options for deploying a self-hosted machine: - **Railway**: One-click-deploy a Triplit server using Railway. This is the easiest way to get started with a self-hosted machine, and won't require any configuration. - **Docker**: Deploy a Triplit server using Docker on a platform of your choice. This will require you to configure your server with the necessary environment variables. We plan on adding many more one-click-deploy options in the future, so stay tuned! #### Configure your server  If you're not using one of the one-click deploy options, you'll need to configure your server to accept requests from the Triplit Dashboard. <Callout type="warning" emoji="⚠️"> If you plan to connect your self-hosted Triplit server to the Triplit Dashboard and use JWTs for authentication and permission within Triplit, EXTERNAL_JWT_SECRET should only be set on your Triplit Dashboard. Ensure the env var is NOT included wherever you deployed your Docker image. Otherwise, you may encounter errors related to invalid JWTs and JWT signatures. </Callout> ##### `JWT_SECRET` The secret used to sign and verify JWT tokens. To use the Triplit Dashboard, set this to the official Triplit public key, provided below.  ##### `LOCAL_DATABASE_URL`  An absolute path on the server's file system to a directory where the server will store any database files. This is required for durable storage options: `lmdb`, and `sqlite`. ##### `CLAIMS_PATH`  If you are using custom JWTs with nested Triplit-related claims, you can set the `CLAIMS_PATH` environment variable. The server will read the claims at the path specified by `CLAIMS_PATH`. Read the  for more information. ##### `SENTRY_DSN`  If you want to log errors to Sentry, you can set the `SENTRY_DSN` environment variable. The server will automatically log errors to Sentry. ##### `VERBOSE_LOGS`  If you want to log all incoming and outgoing messages and requests, you can set the `VERBOSE_LOGS` environment variable. This can be useful for debugging. ### Add your server's hostname to your project Once you have a Triplit server running and , enter its hostname into the form and click **Connect**. ### Use the dashboard You can use the Triplit dashboard to: - Mint API keys and rotate them as needed - Allow your server to accept external tokens signed with different secrets without modifying your server's code - Manage your data and schema with the  To enable these benefits, your app will connect to a `https://<project-id>.triplit.io` URL. This will route your requests to your self-hosted server. Copy the secrets from the **Overview** tab  into your app's `.env` file. ! </Steps> --- description: Learn about using the Triplit Console to manage your data. --- import Image from 'next/image'; import console from '../../../public/dashboard-screenshots/console-main.png'; import createCollection from '../../../public/dashboard-screenshots/create-collection.png'; import insertAttribute from '../../../public/dashboard-screenshots/insert-attribute.png'; import insertEntity from '../../../public/dashboard-screenshots/insert-entity.png'; # Triplit Console <Image src={console} alt="The Triplit Console" width={'100%'} style={{ borderRadius: 16, marginTop: 32 }} /> The Triplit Console is a graphical interface for managing your data and schema. It's available for Triplit Cloud projects, whether they're connected to a managed machine or a self-hosted one. ## Features The Triplit Console offers a range of features to help you manage your data and schema: ### Manage your data You can insert entities into your collections. <Image src={insertEntity} alt="Inserting an entity" width={'100%'} style={{ borderRadius: 16, marginTop: 32 }} /> And update them inline. --- description: Learn how to update your application for the upgraded API in Triplit 1.0. --- # Migrating to Triplit 1.0 Triplit 1.0 is here. It's a major upgrade that includes significant improvements to performance and reliability. There are also several improvements to the API, including: - Simplified query syntax and the removal of `.build` from the query builder API - More type hinting when defining permissions and relations in a schema. - Easier self-hosted server setup with fewer required environment variables. Because Triplit 1.0 uses a new data storage format and redesigned sync protocol, client and server must be updated in tandem, and neither will be backwards compatible with their pre-1.0 counterparts. The server upgrade involves a data migration. If you're using Triplit Cloud, we'll handle this for you when you're ready to upgrade. If you're self-hosting, you can follow the instructions in the  below. ## Query builder ### Capitalization and `.build` Anywhere you have a Triplit query defined in your app, you'll need to make some subtle updates. Every builder method  is now capitalized. In addition, you no longer need to call `.build` at the end of your query. Here's an example of a query before and after the upgrade: Before:  After:  ### `SyncStatus` The `SyncStatus` parameter has been changed from a query builder method to an option on `TriplitClient.subscribe` and `TriplitClient.fetch` and their permutations . Before:  After:  ### `subquery` builder method The `.subquery` builder method has been replaced with two new methods: `.SubqueryOne` and `.SubqueryMany`. Previously the `.subquery` method required a `cardinality` parameter to specify whether the subquery was for a single or multiple entities. These new methods are more explicit and provide better type hinting. Before:  After:  ## Schema ### Reorganized schema sections and better type hinting - Relations in your schema are now defined in a `relationships` section. This makes it easier to see at a glance how your data is connected, and provides better type hinting when you're working with your schema. - The `ClientSchema` type has been removed in favor of an `S.Collections` method that gives better type hinting when defining your schema. Here's an example of a schema before and after the upgrade: Before:  After:  ### New `S.Default.Set.empty` option The `S.Default.Set.empty` is a new option for the `default` option in a `Set` attribute. Here's how to use it:  ### Changed type helpers The `EntityWithSelection` type, previously used to extract an entity from the schema with a specific selection, has been replaced with a `QueryResult` type. This new type is more flexible and provides better type hinting when working with your schema. Before:  After:  ## Client configuration ### `storage` changed The `storage` option in the `TriplitClient` no longer accepts an object with `cache` and `outbox` properties. Instead, you can continue to pass in the simple string values `memory` or `indexeddb`, or in the uncommon case that you are creating your own storage provider, an instance of a `KVStore` . If you need to specify a name for your IndexedDB database, you can pass in an object with a `type` property set to `'indexeddb'` and a `name` property set to the desired name of your database. Before:  After:  ### Storage imports If you chose to import storage providers directly, previously our storage providers were only exported from `@triplit/db`, so you needed to install `@triplit/db` alongside `@triplit/client`. Providers are now directly exported by `@triplit/client`. Before:  After:  For most purposes, you should only need to install `@triplit/client`. ### `experimental.entityCache` removed The `experimental.entityCache` option has been removed from the `TriplitClient` configuration. This option is no longer needed in Triplit 1.0. ## Client methods ### Deleting optional attributes Previously, deleting an optional attribute in the `TriplitClient.update` method would remove the key from the entity. Any attribute wrapped in `S.Optional` would be of type `T | undefined`. Now, deleting an optional attribute will set the attribute to `null`, and the attribute will be of type `T | undefined | null`. ### `insert`, `update`, `delete`, `transact` return types changed These methods no longer return a `{ txId, output }` object. Instead, if they have an output, e.g. `insert`, they return it directly. Before:  After:  Retrying and rollback with `TxId` is no longer necessary, as the sync engine now handles rollbacks with a new API. See below for more details. ### Sync error handling methods changed The `TriplitClient` methods `retry`, `rollback`, `onTxSuccessRemote`, and `onTxFailureRemote` have been replaced with a new API for handling sync errors. The new methods include `onFailureToSyncWrites`, `onEntitySyncError`, `onEntitySyncSuccess`, `clearPendingChangesForEntity` and `clearPendingChangesForAll`. Instead of registering callbacks for a specific transaction, you may register callbacks for a specific entity. It is important that you handle sync errors in your app code, as the sync engine can get blocked if the entity that causes the error is not removed from the outbox or updated. Before:  After:  ### `getSchemaJSON` removed The `getSchemaJSON` method has been removed from the `TriplitClient` API, as the schema is now JSON by default. Before:  After:  ## Frameworks ### Angular Triplit previously maintained two sets of Angular bindings: the signal-based `injectQuery` and the observable-based `createQuery`. In Triplit 1.0, we've removed the signal-based bindings in favor of the more flexible and powerful observable-based bindings. If you're using the signal-based bindings, you'll need to update your app to use the observable-based bindings. Generally this means adopting the  in your templates or by using the  to translate them to signals. ### Expo / React Native #### Expo SQLite storage provider There's a new storage provider for Expo applications that use the `expo-sqlite` package. You can now use the `ExpoSQLiteKVStore` storage provider to store data on the device. This provider is available in the `@triplit/client` package.  You should use a new name for your SQLite database to avoid conflicts with any legacy Triplit databases on the device. #### @triplit/react-native We moved relevant React Native code to a new `@triplit/react-native` package. This includes various helpers for configuring your app with Expo and Triplit and re-exports the same hooks available in the `@triplit/react` package. You can find updating information on setting up a react project with Triplit . ### HTTP API If you're using the  to interact with the HTTP API, you won't need to make any changes to your code. If you're interacting with the API directly : - The `/fetch` route now returns an flatter JSON payload of query results , rather than a JSON object of the shape`{ result :  }`. So for this query:  Before:  After:  While the query builder methods  have changed capitalization, keys in a json query payload remain lowercase. ## Migrating your server ### Triplit Cloud If you're on a Triplit Cloud database, you don't need to do anything to upgrade your server. We'll handle the upgrade for you when you're ready to upgrade. Just contact us in the  or at . ### Self hosted If you're self hosting, you'll need to migrate your own database. Triplit provides a few tools that are helpful for this process, but it is up to you to ensure you safely migrate the database for your application's needs. If you are using SQLite for storage  and you are re-using the same machine, it is recommended that you delete your existing database file during the migration. These files should exist at the path you have specified by your `LOCAL_DATABASE_URL` variable. This isn't strictly necessary, but highly recommended as it will improve the performance of the database and ensures no data from V0 is carried over. There are a variety of ways you could go about migrating data from V0 to V1, but generally the steps to migrate your server are: 1. If you have outside traffic to your server and want to re-use your machine, we recommend that you disable that traffic during the migration. For example, if you are directly serving a docker container you can change the port that the container is exposed on. Alternatively, you could deploy to a different machine that won't have outside traffic. 2. Take a snapshot of your database with `triplit snapshot create`. 3. If you are re-using your machine, delete your existing database file. 4. Pointing to the server you would like to push to, run `triplit snapshot push --snapshot=<snapshotId>`. 5. With an updated schema as described above, run `triplit schema push`. 6. Congratulations, you have successfully migrated your server from V0 to V1! If things seem stable, you may now re-enable traffic to your server. If anything seems incorrect, you should have your data saved in a snapshot. If you would like any help or have any questions, please reach out to us in the  or at . import { Callout } from 'nextra/components'; import Image from 'next/image'; import dashboardOverview from '../../public/dashboard-overview.png'; import dashboardDeployments from '../../public/dashboard-deployments.png'; # Getting Started with Triplit Cloud v2 <Callout type="warning" emoji="⚠️"> Triplit Cloud is currently in preview. There may be bugs, breaking changes, and other issues. Please report any issues you encounter or any feedback you have to our  or . </Callout> <Callout type="info" emoji="ℹ️"> To get access to Triplit Cloud, join our . </Callout> This tutorial will show you how to deploy a project to Triplit Cloud. It will cover 1.  2.  3.  ## Prerequisites - A Triplit project. If you don't have one, you can create one by following the  guide. - The Triplit CLI. You can install it by running `npm install -g @triplit/cli`. ## Authenticate with Triplit Cloud To authenticate with Triplit Cloud, run the following command from inside your project directory:  This will ask you to enter an email, and will send a one-time password to your email. After entering the one-time password, you will be authenticated with Triplit Cloud. <Callout type="info" emoji="ℹ️"> If you already have access to the , make sure you enter the same email you used to sign up for the dashboard. </Callout> You'll also be asked to select an organization or create a new one. If you're part of an organization, you can select it from the list. If you're not part of an organization, you can create a new one.  You can then run `triplit whoami` to verify that you are authenticated.  <Callout type="info" emoji="ℹ️"> If you want to set up multiple organizations and switch between them, run `triplit org`. </Callout> ## Create and link to a cloud project <Callout type="warning" emoji="⚠️"> If you've used Triplit Cloud in its prior iteration, your existing projects will be marked as "Legacy" in the dashboard and are wholly separate from the deploy flow described here. If you have any questions or need help, please reach out to us on . </Callout> To deploy a project to Triplit Cloud, you need to create a cloud project. To create a cloud project, run the following command:  This will create a project in Triplit Cloud that will be associated with the current organization you're working with. This command will also create a `triplit.config.json` file in your project directory that looks like this:  <Callout type="info" emoji="ℹ️"> If at any time you want to change the cloud project that your local project is linked to, run `triplit project link`. </Callout> ## Copy in your environment variables To connect the Triplit Client in your App to the Triplit Cloud project you created, you'll need to have a properly configured `.env` file in your project. You can view the environment variables from the Triplit Cloud project by running the following command:  This will print a url to the Triplit Cloud dashboard where you can manage your project. You can then copy the environment variables from the dashboard and paste them into your `.env` file. <Image src={dashboardOverview} style={{ borderRadius: 8, marginTop: 16 }} width={800} height={800} alt="The Triplit Dashboard " /> ## Deploy your project This part's easy: just run `triplit deploy`. This will bundle your project, including it's `./triplit/schema.ts` file, and deploy it to Triplit Cloud.  If you've used a previous iteration of Triplit Cloud and are expecting to run various `triplit migrate` commands, these are no longer necessary. If you update your schema, simply run `triplit deploy` again and your changes will be reflected in the cloud. ## Viewing your deployments You can view your deployments in the Triplit Cloud dashboard. To open the dashboard, run the following command again:  Go to the "Deployments" tab to see all of your deployments. <Image src={dashboardDeployments} style={{ borderRadius: 8, marginTop: 16 }} width={800} height={800} alt="The Triplit Dashboard " />