import Script from 'next/script'; export default function App { return } ); } --- description: Learn how to setup user auth for your Triplit application. --- import { Steps, Callout, Tabs, Tab } from 'nextra/components'; # Authentication In this guide we'll show you how to identify users connecting to your Triplit server and how to model access control with that information. By the end of the guide, you'll be able to define a schema that allows users to insert and update their own data, but not other users' data: ### Choose an authentication provider You'll likely start out your project using the `anon` and `service` tokens provided by default. These are great for getting started, but don't provide any user-specific information that you'll need to model access control. Choose from one of the many authentication providers that issue JWTs: - : read the Triplit integration guide - : read the Triplit integration guide - - - ...or any other provider that issues JWTs ### Allow your Triplit server to verify JWTs If you're using a third-party authentication provider, you'll need to provide the public key or secret that it's using to sign JWTs to your Triplit server so it can verify them. Triplit supports both symmetric and asymmetric JWT encryption algorithms. If you're connecting to a `triplit.io` URL, . If you're fully self-hosting Triplit , you'll need to set the `EXTERNAL_JWT_SECRET` environmental variable to the public key or symmetric secret. ### Pass the token to Triplit Once you have your authentication provider set up in your app and your user is signed in, you'll need to pass the JWT to Triplit. This is done by calling `startSession` on the `TriplitClient` instance. Connections to the server are managed with the Sessions API. Read more about it . ### Add permissions to your schema Access control to data on a Triplit server is defined by permissions in the schema. Permissions can reference the JWT claims that are passed to Triplit. Once you've added permissions, you need to run `npx triplit schema push` to have them take effect on a deployed server . These permissions will allow any authenticated user to read all blog posts, but only allow them to insert, update, and delete their own posts. Notice that permissions are _defined as query filters_. This means that a permissions can be as complex as a query, and use `or`, `exists` and other query operators. Permissions can also reference relationships and/or any of the JWT claims on the user's `$token`. In this case, we're using the `sub` claim to identify the user. This is the default claim that most authentication providers will use to identify the user. ### Use token claims when inserting or updating data When Triplit is given a JWT token, it makes the decoded claims available through the `TriplitClient.vars.$token`. If your collections have fields that are set to identifiable information from the token, you can access it there and use it in your calls to `insert` or `update`. Using the `blogPosts` example from above, you can set the `authorId` field to the user's `sub` claim when inserting a new post: ### Add additional roles . Triplit has two default roles: `authenticated` and `anonymous`. The `authenticated` role is used for any user that connect with a JWT that has a `sub` claim. The `anonymous` role is assigned to any client that connects with the Triplit-generated `anon` token. This is a special token that is safe to use on the client side and should be used when no user is logged in. You may find that you need to create additional roles for your application. For example, you may have an admin role that is distinct from a normal user. See the for more information. ## Debugging authentication If you are having trouble connecting to the server, there are a few things to try: - pass the `logLevel: 'debug'` option to the `TriplitClient` constructor to get more information about the connection process and failures. - confirm that your `serverUrl` is correct and that the server is running. - check that the JWT being issued by your authentication provider is valid and has not expired. You can use to decode the JWT and check its claims. - check that the your Triplit server is configured to accept the JWT. If you're using a third-party authentication provider, make sure that the public key or secret is set correctly in your Triplit server. If you're using a self-hosted server, make sure that the `EXTERNAL_JWT_SECRET` environmental variable is set. --- 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. This guide assumes you have a Triplit project set up. If you don't have one, you can create one by following the guide. ### 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`. Here's an example with Clerk's React bindings: You'll note that we're using the `refreshHandler` option 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. Now that you have a user auth system set up, you can add permissions to your Triplit schema. By default, the JWT issued by Clerk will set the `sub` claim to the authenticated user's unique identifier. The server will apply the default `authenticated` role the token. For a given collection, you can define a permission that only allows any authenticated user to read all posts but only mutate their own. When creating `posts`, you should ensure that the `authorId` is set to the `sub` claim, either taken from the token or the Supabase session. If you need to model more complex roles or permissions, . --- 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. This guide assumes you have a Triplit project set up. If you don't have one, you can create one by following the guide. ### 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 permissions to your Triplit schema. By default, the JWT issued by Supabase will set the `sub` claim to the authenticated user's unique identifier. The server will apply the default `authenticated` role the token. For a given collection, you can define a permission that only allows any authenticated user to read all posts but only mutate their own. When creating `posts`, you should ensure that the `authorId` is set to the `sub` claim, either taken from the token or the Supabase session. If you need to model more complex roles or permissions, . --- 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. `TriplitClient.startSession` will automatically end the previous session if one is already active. ### 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. 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. ## `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. Calling `endSession` **will not** clear the the client's database. If you want to clear the cache, you should call `client.clear`. ## `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 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: 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`. browser console --- 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. This is distinct from the parameter on a query, which indicates how you wish to query your local database. 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. `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 . - `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: When using `insert` to upsert an existing record, any defaults on the schema will be applied even if the record already exists. --- 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://.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. 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. 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 ). - `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 . ## Experimental options These options are experimental and may change in the future. All keys fall under the `experimental` key. - `onDatabaseInit` is a hook that runs after your client-side database has initialized and before any client operations are run and syncing begins. This hook provides a DB instance and an `event` which tells you information about the database startup state. --- 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 . ### Caching By default, the `TriplitClient` will cache all IndexedDB data in memory for fast access . If you want to disable this, you can set the `cache` option to `false` when creating the `TriplitClient`. ## 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. ## Existing projects If have an existing Angular project, you install the hooks provided by `@triplit/angular`: ## 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: ### 2. 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. ### 3. Use React hooks Triplit's hooks are also exported via `@triplit/react-native`, so you can use them in your components just like you would in a web app. ### Additional configuration #### Update metro.config.js If you are using a Metro version before `0.82.0`, you will need to add a custom Metro config to your project. This is encompasses most users using Expo 52 and below. This is because Triplit uses some features that are not supported by the Metro bundler, notably the field. To determine the version of Metro that is installed, run the following command: Below is an example output with version `0.82.3` installed: If you are using a version prior to `0.82.0`, Triplit provides a utility for generating a custom Metro config that will resolve these exports. 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. #### 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: ### 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:` would become `http://:`. ## 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. ### Existing projects If you have an existing React project, you can install the hooks provided by `@triplit/react`: ## 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. 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`. ## 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 Solid bindings for the Triplit client in your app. --- import { Tabs, Tab, Callout } from 'nextra-theme-docs'; import CreateTriplitAppTabs from '../../components/CreateTriplitAppTabs.mdx'; # Solid ### New projects The fast way to get started with Triplit is to use Create Triplit App which will scaffold a Vite application with Triplit. Choose `Solid` when prompted for the frontend framework. ### Existing projects If you have an existing Solid project, you can add the hooks provided by `@triplit/solid`: ## useQuery The `useQuery` hook subscribes to the provided query inside your Solid component and will automatically unsubscribe from the query when the component unmounts. The result of the hook is an object with the following signal accessor and getter 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. - `setQuery`: a setter function that can be used to update the query and cleanup the previous query. ## 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 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" . ### 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. ### Existing projects If you have an existing Svelte or Svelte project, you can add the hooks provided by `@triplit/svelte`: ## 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. ## useQueryOne `useQueryOne` is like `useQuery` in that it subscribes to the provided query, but adds a `Limit` to the query. It returns the same properties as `useQuery`, except that `results` becomes `result`, which is a single entity or `null` if no entity was found. ## useEntity `useEntity` subscribes to the provided entity in the collection, returning the entity or `null` if the entity does not exist. It returns the same properties as `useQuery`, except that `results` becomes `result`, which is a single entity or `null` if no entity was found. ## 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: ## `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. ### Existing projects If have an existing Vue project, you install the hooks provided by `@triplit/vue`: ## 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