Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: add "Using Prisma with Turso" database guide #5399

Merged
merged 48 commits into from
Nov 3, 2023
Merged
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
d1e2b36
add section on embedded databases
ruheni Oct 24, 2023
325b815
more updates to the Turso guide
ruheni Oct 24, 2023
f86b674
chore: update heading levels
ruheni Oct 24, 2023
d24b348
Apply suggestions from code review
ruheni Oct 25, 2023
6c08f0d
update db name used in guide
ruheni Oct 25, 2023
de2b5d4
update guide
ruheni Oct 31, 2023
dcae7f6
chore: fix copy-pasta mistake
ruheni Oct 31, 2023
9721eb6
docs: link to libSQL manifesto
ruheni Oct 31, 2023
54568b6
chore: add features an differences between sqlite and turso
ruheni Oct 31, 2023
037469d
reorder content
ruheni Oct 31, 2023
c38e6af
Merge branch 'main' into turso-guide
ruheni Oct 31, 2023
bb0c219
indent content
ruheni Oct 31, 2023
64ecbff
Create 890-Neon
raoufchebri Jun 7, 2023
633cd01
docs: update Neon docs
ruheni Oct 24, 2023
23efa0d
update heading
ruheni Oct 24, 2023
004470e
Apply suggestions from code review
ruheni Oct 25, 2023
6a97d9a
chore: update top block
ruheni Oct 25, 2023
7d2338a
add serverless driver section
ruheni Oct 25, 2023
95872f2
update admonition about database_url env var
ruheni Oct 25, 2023
d543aca
Apply suggestions from code review
ruheni Oct 27, 2023
f4e4c61
Apply suggestions from code review
ruheni Oct 27, 2023
d7589b7
update example connection string
ruheni Oct 30, 2023
0b30410
minor edits
ruheni Oct 30, 2023
ecdd362
add section on differences to consider
ruheni Oct 30, 2023
e50dd74
chore: delete neon page from pr
ruheni Oct 31, 2023
49207e4
chore: reorder content
ruheni Oct 31, 2023
14c831c
add turso's logo
ruheni Oct 31, 2023
d7499e6
chore: more modifications
ruheni Oct 31, 2023
0267e19
reword
ruheni Oct 31, 2023
23791db
reword
ruheni Oct 31, 2023
d98a22b
reorder content
ruheni Oct 31, 2023
39315b3
Merge branch 'main' into turso-guide
ruheni Nov 1, 2023
37170ba
update content
ruheni Nov 1, 2023
4e9b645
add app middleware example
ruheni Nov 1, 2023
e97297f
edit middleware example
ruheni Nov 1, 2023
57f40c2
update middleware example
ruheni Nov 1, 2023
20f3198
update embedded replica content
ruheni Nov 2, 2023
831171e
Merge branch 'main' into turso-guide
ruheni Nov 2, 2023
0d4748e
Apply suggestions from code review
ruheni Nov 2, 2023
b386441
Apply suggestions from code review
ruheni Nov 2, 2023
5f5706a
update image style
ruheni Nov 3, 2023
f6f7f28
indent code blocks
ruheni Nov 3, 2023
10cf9a6
update how to connect to connect and query a Turso db section
ruheni Nov 3, 2023
d368929
more modifications
ruheni Nov 3, 2023
cb2964d
Merge branch 'main' into turso-guide
ruheni Nov 3, 2023
aaaab90
fix styling
ruheni Nov 3, 2023
6ddcbc6
update headline
ruheni Nov 3, 2023
5f8974d
Merge branch 'main' into turso-guide
ruheni Nov 3, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
202 changes: 202 additions & 0 deletions content/300-guides/050-database/900-turso.mdx
ruheni marked this conversation as resolved.
Show resolved Hide resolved
ruheni marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
---
title: 'Using Prisma with Turso'
metaTitle: 'Using Prisma with Turso (Early Access)'
metaDescription: 'Guide to using Prisma with Turso'
tocDepth: 3
---

<TopBlock>

This guide discusses the concepts behind using Prisma and Turso, explains the commonalities and differences between Turso and other database providers, and leads you through the process for configuring your application to integrate with Turso.

Prisma support for Turso is currently in [Early Access](/about/prisma/releases#early-access). We would appreciate your feedback in this [GitHub discussion](https://github.com/prisma/prisma/discussions/21345).

</TopBlock>

## What is Turso?

<img
src="https://avatars.githubusercontent.com/u/139391156?s=200&v=4"
style="margin:auto; width: 20%; padding-left: 20px; float:right; "
alt="Turso's logo"
/>
ruheni marked this conversation as resolved.
Show resolved Hide resolved

[Turso](https://turso.tech/) is an edge-hosted, distributed database that's based on [libSQL](https://turso.tech/libsql), an open-source and open-contribution fork of [SQLite](https://sqlite.org/), enabling you to bring data closer to your application and minimize query latency. Turso can also be hosted on a remote server.

<Admonition type="warning">

Support for Turso is available in [Early Access](/about/prisma/releases#early-access) from Prisma versions 5.4.2 and later.

</Admonition>

## Commonalities with other database providers
ruheni marked this conversation as resolved.
Show resolved Hide resolved
ruheni marked this conversation as resolved.
Show resolved Hide resolved

libSQL is 100% compatible with SQLite. libSQL extends SQLite and adds the following features and capabilities:

- Support for replication
- Support for automated backups
- Ability to embed Turso as part of other programs such as the Linux kernel
- Supports user-defined functions
- Support for asynchronous I/O

> To learn more about the differences between libSQL and how it is different from SQLite, see [libSQL Manifesto](https://turso.tech/libsql-manifesto).

Many aspects of using Prisma with Turso are just like using Prisma with any other relational database. You can still:

- model your database with the [Prisma Schema Language](/concepts/components/prisma-schema)
- use Prisma's existing [`sqlite` database connector](/concepts/database-connectors/sqlite) in your schema
- use [Prisma Client](/concepts/components/prisma-client) in your application to talk to the database server at Turso

## Differences to consider

There are a number of differences between Turso and SQLite to consider. You should be aware of the following when deciding to use Turso and Prisma:

- **Remote and embedded SQLite databases**. libSQL uses HTTP to connect to the remote SQLite database. libSQL also supports remote database replicas and embedded replicas. Embedded replicas enable you to replicate your primary database inside your application.
- **Making schema changes**. Since libSQL uses HTTP to connect to the remote database, this makes it incompatible with Prisma Migrate. However, you can use [`prisma migrate diff`](/reference/api-reference/command-reference#migrate-diff) <span class="api"></span> to create a schema migration and then apply the changes to your database using [Turso's CLI](https://docs.turso.tech/reference/turso-cli).

## Connect and query your primary database
ruheni marked this conversation as resolved.
Show resolved Hide resolved
ruheni marked this conversation as resolved.
Show resolved Hide resolved

<br />

<details>

<summary>
Expand to learn how to provision a database and retrieve your credentials on
Turso
</summary>

Ensure that you have the [Turso CLI](https://docs.turso.tech/reference/turso-cli) installed to manage your databases.

To provision a database on Turso, run the following command:
ruheni marked this conversation as resolved.
Show resolved Hide resolved

```terminal
turso db create turso-prisma-db
```

Retrieve the database's connection string:
ruheni marked this conversation as resolved.
Show resolved Hide resolved

```terminal
turso db show turso-prisma-db
```

3. Create an authentication token that will allow you to connect to the database:

```terminal
turso db tokens create turso-prisma-db
```

4. Update your `.env` file with the authentication token and connection string:

```text file=.env
TURSO_AUTH_TOKEN="eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9..."
TURSO_DATABASE_URL="libsql://turso-prisma-db-user.turso.io"
```
ruheni marked this conversation as resolved.
Show resolved Hide resolved

</details>

To get started, enable the `driverAdapters` Preview feature flag:

```prisma highlight=3;add
generator client {
provider = "prisma-client-js"
previewFeatures = ["driverAdapters"]
}

datasource db {
provider = "sqlite"
url = "file:./dev.db"
}
```

Generate Prisma Client:

```terminal
npx prisma generate
```

Install the libSQL database client and Prisma driver adapter for libSQL packages:

```terminal
npm install @libsql/client @prisma/adapter-libsql
```

Update your Prisma Client instance:

```ts
import { PrismaClient } from '@prisma/client'
import { PrismaLibSQL } from '@prisma/adapter-libsql'
import { createClient } from '@libsql/client'

const libsql = createClient({
url: `${process.env.TURSO_DATABASE_URL}`,
authToken: `${process.env.TURSO_AUTH_TOKEN}`,
})

const adapter = new PrismaLibSQL(libsql)
const prisma = new PrismaClient({ adapter })
```

You can use Prisma Client as you normally would with full type-safety in your project.

## How to manage schema changes

Prisma Migrate and Introspection workflows are currently not supported when working with Turso. This is because Turso uses HTTP to connect to your database, which Prisma Migrate doesn't support.

To update your database schema:

1. Generate a migration file using `prisma migrate dev` against a local SQLite database:
ruheni marked this conversation as resolved.
Show resolved Hide resolved

```terminal
npx prisma migrate dev --name init # Migration name
```

2. Apply the migration using Turso's CLI:

```terminal
turso db shell turso-prisma-db < ./prisma/migrations/20230922132717_init/migration.sql # Replace `20230922132717_init` with the existing migration
ruheni marked this conversation as resolved.
Show resolved Hide resolved
```

For subsequent migrations, repeat the above steps to apply changes to your database. This workflow does not support tracking the history of applied migrations.
ruheni marked this conversation as resolved.
Show resolved Hide resolved

## How to connect and query from an embedded replica

Turso supports [embedded replicas](https://blog.turso.tech/introducing-embedded-replicas-deploy-turso-anywhere-2085aa0dc242). Turso's embedded replicas enable you to have a copy of your primary, remote database _inside_ your application. Embedded replicas behave similarly to a local SQLite database. Database queries are faster because your database is inside your application.

When your app initially establishes a connection to your database, the primary database will fulfill the query:

![Embedded Replica: First remote read](./images/embedded-replica-remote-read.png)

Turso will (1) create an embedded replica inside your application and (2) copy data from your primary database to the replica so it is locally available:

![Embedded Replica: Remote DB Copy](./images/embedded-replica-create-replica.png)

The embedded replica will fulfill subsequent read queries. The libSQL client provides a [`sync()`](<https://docs.turso.tech/libsql/client-access/javascript-typescript-sdk#client-capability-summary:~:text=an%20interactive%20transaction-,sync(),-Synchronize%20the%20embedded>) method which you can invoke to ensure the embedded replica's data remains fresh.

![Embedded Replica: Local DB reads](./images/embedded-replica-read.png)

With embedded replicas, this setup guarantees a responsive application, because the data will be readily available locally and faster to access.

Like a read replica setup you may be familiar with, write operations are forwarded to the primary remote database and executed before being propagated to all embedded replicas.

![Embedded Replica: Write operation propagation](./images/embedded-replica-write-propagation.png)

1. Write operations propagation are forwarded to the database.
1. Database responds to the server with the updates from 1.
1. Write operations are propagated to the database replica.

How often to synchronize you need to synchronize data between your remote database and embedded replica is dependent on your application's data consistency needs. For example, you can use either middleware functions (e.g. Express and Fastify) or a cron job to synchronize the data.
ruheni marked this conversation as resolved.
Show resolved Hide resolved

To get started using embedded replicas with Prisma, add the `sync()` method from libSQL in your application. The example below shows how you can synchronize data using Express middleware.
ruheni marked this conversation as resolved.
Show resolved Hide resolved

```ts highlight=5-8;add;
import express from 'express'
const app = express()

// ... the rest of your application code
app.use(async (req, res, next) => {
await libsql.sync()
next()
})

app.listen(3000, () => console.log(`Server ready at http://localhost:3000`))
```
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading