Skip to content

Commit 776bb74

Browse files
Feat: DR-6472 SQLite MySQL added to embedded studio docs (#7430)
* Added SQLite and MySQL to embedding studio docs * Added SQLite and MySQL to embedding studio guide docs * Possible over promise removed * unneeded import removed * broken link removed * Update content/800-guides/360-embed-studio-nextjs.mdx --------- Co-authored-by: Ankur Datta <64993082+ankur-arch@users.noreply.github.com>
1 parent 06f1188 commit 776bb74

File tree

2 files changed

+727
-52
lines changed

2 files changed

+727
-52
lines changed

content/250-postgres/300-database/675-prisma-studio/100-embedding-studio.mdx

Lines changed: 191 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ toc: true
1010

1111
Prisma Studio can be embedded in your own application via the [`@prisma/studio-core`](https://www.npmjs.com/package/@prisma/studio-core) package.
1212

13-
It provides `Studio`, a React component which renders Prisma Studio for your database. The `Studio` component accepts an executor that calls a `/studio` endpoint in your backend. The backend uses your `DATABASE_URL` (connection string) to connect to the correct Prisma Postgres instance and execute the SQL query.
13+
It provides `Studio`, a React component which renders Prisma Studio for your database. The `Studio` component accepts an executor that calls a `/studio` endpoint in your backend. The backend uses your `DATABASE_URL` (connection string) to connect to the correct database instance (PostgreSQL, SQLite, or MySQL) and execute the SQL query.
1414

1515
:::tip
1616
If you want to see what embedded Studio looks like, **[check out the demo](https://github.com/prisma/studio-core-demo) on GitHub**!
@@ -29,29 +29,53 @@ You can embed Prisma Studio in your own app in various scenarios:
2929
- Frontend: A React application
3030
- Backend:
3131
- A server-side application to expose the `/studio` endpoint (e.g. with Express or Hono)
32-
- A Prisma Postgres instance (you can create one with `npx prisma init --db`)
32+
- A database instance (PostgreSQL, SQLite, or MySQL)
33+
34+
## Database support
35+
36+
Embedded Prisma Studio supports the following databases:
37+
38+
- **PostgreSQL**
39+
- **SQLite**
40+
- **MySQL**
3341

3442
:::note
35-
The embeddable version of Prisma Studio will be available for other databases in combination with Prisma ORM soon.
43+
The implementation pattern is similar across all databases - you just need to use the appropriate executor and adapter for your database type.
3644
:::
3745

3846
## Installation
3947

4048
Install the npm package:
4149

42-
```terminal
50+
```bash
4351
npm install @prisma/studio-core
4452
```
4553

54+
### Additional dependencies
55+
56+
Depending on your database type, you may need additional packages:
57+
58+
```bash
59+
# For SQLite support
60+
npm install better-sqlite3
61+
62+
# For MySQL support
63+
npm install mysql2
64+
```
65+
66+
PostgreSQL support is included with `@prisma/studio-core` and requires no additional dependencies.
67+
4668
## Frontend setup
4769

4870
In your React app, you can use the `Studio` component to render the tables in your database via Prisma Studio. It receives an _executor_ which is responsible for packaging the current SQL query in an HTTP request (also allowing for custom headers/payloads) and sending it to the `/studio` endpoint in your backend.
4971

72+
The implementation varies slightly depending on your database type. Choose the appropriate section below:
73+
5074
> Check out the [demo](https://github.com/prisma/studio-core-demo/blob/main/frontend/index.tsx) on GitHub for a full reference implementation.
5175
52-
### Minimal implementation
76+
### PostgreSQL implementation
5377

54-
Here's what a minimal implementation looks like:
78+
Here's what a minimal implementation looks like for PostgreSQL:
5579

5680
```tsx
5781
import { Studio } from "@prisma/studio-core/ui";
@@ -79,9 +103,69 @@ function App() {
79103
}
80104
```
81105

106+
### SQLite implementation
107+
108+
Here's what a minimal implementation looks like for SQLite:
109+
110+
```tsx
111+
import { Studio } from "@prisma/studio-core/ui";
112+
import { createSQLiteAdapter } from "@prisma/studio-core/data/sqlite-core";
113+
import { createStudioBFFClient } from "@prisma/studio-core/data/bff";
114+
import "@prisma/studio-core/ui/index.css"
115+
116+
function App() {
117+
const adapter = useMemo(() => {
118+
// 1. Create a client that points to your backend endpoint
119+
const executor = createStudioBFFClient({
120+
url: "http://localhost:4242/studio",
121+
});
122+
123+
// 2. Create a SQLite adapter with the executor
124+
const adapter = createSQLiteAdapter({ executor });
125+
return adapter;
126+
}, []);
127+
128+
return (
129+
<Layout>
130+
<Studio adapter={adapter} />
131+
</Layout>
132+
);
133+
}
134+
```
135+
136+
### MySQL implementation
137+
138+
Here's what a minimal implementation looks like for MySQL:
139+
140+
```tsx
141+
import { Studio } from "@prisma/studio-core/ui";
142+
import { createMySQLAdapter } from "@prisma/studio-core/data/mysql-core";
143+
import { createStudioBFFClient } from "@prisma/studio-core/data/bff";
144+
import "@prisma/studio-core/ui/index.css"
145+
146+
function App() {
147+
const adapter = useMemo(() => {
148+
// 1. Create a client that points to your backend endpoint
149+
const executor = createStudioBFFClient({
150+
url: "http://localhost:4242/studio",
151+
});
152+
153+
// 2. Create a MySQL adapter with the executor
154+
const adapter = createMySQLAdapter({ executor });
155+
return adapter;
156+
}, []);
157+
158+
return (
159+
<Layout>
160+
<Studio adapter={adapter} />
161+
</Layout>
162+
);
163+
}
164+
```
165+
82166
### Custom headers/payload implementation
83167

84-
Here's what an implementation with custom headers/payload looks like:
168+
Here's what an implementation with custom headers/payload looks like (works for all database types):
85169

86170
```tsx
87171
import { Studio } from "@prisma/studio-core/ui";
@@ -102,8 +186,10 @@ function App() {
102186
}
103187
});
104188

105-
// 2. Create a Postgres adapter with the executor
106-
const adapter = createPostgresAdapter({ executor });
189+
// 2. Create a database adapter with the executor
190+
const adapter = createPostgresAdapter({ executor }); // PostgreSQL
191+
// const adapter = createSQLiteAdapter({ executor }); // SQLite
192+
// const adapter = createMySQLAdapter({ executor }); // MySQL
107193
return adapter;
108194
}, []);
109195

@@ -174,15 +260,17 @@ With this setup, Studio inherits your custom colors, borders, and typography rul
174260

175261
Here's an overview of the key concepts in your frontend:
176262
- **Executor**: The bridge between Studio and your backend, it's created using the `createStudioBFFClient` function
177-
- **Adapter**: Handles Postgres-specific query formatting
263+
- **Adapter**: Handles database-specific query formatting (PostgreSQL, SQLite, or MySQL)
178264
- **Custom headers**: Pass authentication tokens, user info, etc.
179265
- **Custom payload**: Send additional context/data with each request
180266

181267
## Backend setup
182268

183-
Your backend needs to expose a `/studio` endpoint where the frontend sends its requests. The implementation below uses `createPrismaPostgresHttpClient` from `@prisma/studio-core`.
269+
Your backend needs to expose a `/studio` endpoint where the frontend sends its requests. The implementation varies depending on your database type. Choose the appropriate section below:
184270

185-
The backend also needs to have access to the Prisma Postgres API key, we recommend setting it as an environment variable as a best practice.
271+
### PostgreSQL backend implementation
272+
273+
The PostgreSQL implementation uses `createPrismaPostgresHttpClient` from `@prisma/studio-core`. This works with Prisma Postgres or any PostgreSQL instance.
186274

187275
> Check out the [demo](https://github.com/prisma/studio-core-demo/blob/main/server/index.ts) on GitHub for a full reference implementation.
188276
@@ -216,9 +304,94 @@ app.post("/studio", async (c) => {
216304
});
217305
```
218306

307+
### SQLite backend implementation
308+
309+
The SQLite implementation uses `createNodeSQLiteExecutor` from `@prisma/studio-core` and requires the `better-sqlite3` package. This works with local SQLite database files.
310+
311+
```ts
312+
import { Hono } from "hono";
313+
import { createNodeSQLiteExecutor } from "@prisma/studio-core/data/node-sqlite";
314+
import { serializeError } from "@prisma/studio-core/data/bff";
315+
import DatabaseSync from "better-sqlite3";
316+
317+
const app = new Hono().use("*", cors());
318+
319+
app.post("/studio", async (c) => {
320+
try {
321+
// 1. Extract the query from the request
322+
const { query } = await c.req.json();
323+
324+
// 2. Read DB URL from env vars (should be a file path)
325+
const url = process.env.DATABASE_URL;
326+
327+
if (!url) {
328+
return c.json([serializeError(new Error("DATABASE_URL is missing"))], 500);
329+
}
330+
331+
// 3. Extract file path from URL and create database connection
332+
const dbPath = url.replace("file:", "");
333+
const database = new DatabaseSync(dbPath);
334+
335+
// 4. Execute the query against SQLite
336+
const [error, results] = await createNodeSQLiteExecutor(database).execute(query);
337+
338+
// 5. Return results or errors
339+
if (error) {
340+
return c.json([serializeError(error)]);
341+
}
342+
343+
return c.json([null, results]);
344+
} catch (err) {
345+
return c.json([serializeError(err)], 400);
346+
}
347+
});
348+
```
349+
350+
### MySQL backend implementation
351+
352+
The MySQL implementation uses `createMySQL2Executor` from `@prisma/studio-core` and requires the `mysql2` package. This works with MySQL instances.
353+
354+
```ts
355+
import { Hono } from "hono";
356+
import { createMySQL2Executor } from "@prisma/studio-core/data/mysql2";
357+
import { serializeError } from "@prisma/studio-core/data/bff";
358+
import mysql from "mysql2/promise";
359+
360+
const app = new Hono().use("*", cors());
361+
362+
app.post("/studio", async (c) => {
363+
try {
364+
// 1. Extract the query from the request
365+
const { query } = await c.req.json();
366+
367+
// 2. Read DB URL from env vars
368+
const url = process.env.DATABASE_URL;
369+
370+
if (!url) {
371+
return c.json([serializeError(new Error("DATABASE_URL is missing"))], 500);
372+
}
373+
374+
// 3. Create MySQL connection pool
375+
const pool = mysql.createPool(url);
376+
377+
// 4. Execute the query against MySQL
378+
const [error, results] = await createMySQL2Executor(pool).execute(query);
379+
380+
// 5. Return results or errors
381+
if (error) {
382+
return c.json([serializeError(error)]);
383+
}
384+
385+
return c.json([null, results]);
386+
} catch (err) {
387+
return c.json([serializeError(err)], 400);
388+
}
389+
});
390+
```
391+
219392
### Custom headers/payload implementation
220393

221-
Here's what a slightly more advanced implementation for the `/studio` endpoint looks like with [Hono](https://hono.dev/). In this case, a multi-tenant scenario is assumed where the frontend sends over a user ID and authentication token which is used on the backend to determine the Prisma Postgres instance that belongs to that user via a hypothetical `determineUrlFromContext` function:
394+
Here's what a slightly more advanced implementation for the `/studio` endpoint looks like with [Hono](https://hono.dev/). In this case, a multi-tenant scenario is assumed where the frontend sends over a user ID and authentication token which is used on the backend to determine the database instance that belongs to that user via a hypothetical `determineUrlFromContext` function:
222395

223396
```ts
224397
// server/index.ts
@@ -242,8 +415,11 @@ app.post("/studio", async (c) => {
242415
// 4. Determine the URL (this is where you'd implement your auth logic)
243416
const url = determineUrlFromContext(customHeader, customPayload);
244417

245-
// 5. Execute the query using Prisma Postgres or Prisma Accelerate
418+
// 5. Execute the query using the appropriate database client
419+
// PostgreSQL:
246420
const [error, results] = await createPrismaPostgresHttpClient({ url }).execute(query);
421+
// SQLite: (requires additional setup with better-sqlite3)
422+
// MySQL: (requires additional setup with mysql2)
247423

248424
// 6. Return results or errors
249425
if (error) {
@@ -258,7 +434,7 @@ app.post("/studio", async (c) => {
258434

259435
- Query object: Contains the SQL query and parameters from Studio
260436
- Custom payload: Additional data sent with each request
261-
- Prisma Postgres client: Executes queries against your database
437+
- Database client: Executes queries against your database (PostgreSQL, SQLite, or MySQL)
262438
- Error handling: Properly serialize errors for Studio to display
263439

264440
## Execution flow

0 commit comments

Comments
 (0)