️ The easiest way to explore and manipulate your data in all of your Prisma projects.
️ The easiest way to explore and manipulate your data in all of your Prisma projects.
Prisma Studio is Prisma's visual editor for exploring and editing your database.
If you already use Prisma ORM in a project, run Studio with:
npx prisma studioPrisma Postgres projects can also use Studio in Prisma Console, which includes additional AI-assisted workflows such as SQL generation and AI-powered filters.
This repository is the OSS home of @prisma/studio-core, the package that powers Prisma Studio in Prisma CLI and Prisma Console.
If you want to work on Studio itself, clone this repository and start the local demo:
pnpm install
pnpm demo:ppgYou do not need this repository to use npx prisma studio in a Prisma project.
Architecture notes live in Architecture/. The package published from this repo is consumed by other Prisma surfaces rather than used as a standalone app directly from this checkout.
Release process notes live in RELEASE.md.
Open an issue for bugs, feature requests, or integration/API questions about embedding @prisma/studio-core at github.com/prisma/studio/issues. Clear reproduction steps, expected behavior, and screenshots make feedback much easier to act on.
Issue-first contributions work best for this repo. Please open an issue before investing in a large pull request; external PRs may not be the preferred path for every change. For general usage questions and broader discussion, join the Prisma Discord.
If you have a security issue to report, contact [email protected].
@prisma/studio-core is the embeddable Prisma Studio package.
It provides the same core experience as Prisma Studio: a visual way to explore schema, browse table data, edit rows, filter/sort/paginate records, inspect relation data, and run SQL queries with an operation log.
This package is published to npm and consumed by Prisma surfaces such as Console and CLI integrations.
Import the UI entrypoint, include the packaged CSS once, and pass a configured adapter into Studio:
…adapter is required.llm is optional and is the single supported AI transport hook for all Studio AI features.{ ok: true, text } or { ok: false, code, message }.llm is omitted, Studio hides AI filtering, AI SQL generation, AI visualization, and Query Insights recommendation affordances entirely.queryInsights is optional. Pass it only when your BFF implements the query-insights procedure; otherwise omit it so Studio hides the Queries view.Studio handles prompt construction, type-aware validation, pre-display SQL validation for AI-generated SQL, correction retries, database-error correction, and conversion into the normal filter, SQL, and visualization surfaces. The host transport only needs to forward the prepared request to an LLM provider and return the typed result.
type StudioLlmRequest = {
task:
| "table-filter"
| "sql-generation"
| "sql-visualization"
| "query-insights";
prompt: string;
};
type StudioLlmResponse =
| { ok: true; text: string }
| {
ok: false;
code:
| "cancelled"
| "not-configured"
| "output-limit-exceeded"
| "request-failed";
message: string;
};Studio treats output-limit-exceeded as a first-class retry signal for SQL generation and visualization correction loops. When sqlLint is available, Studio validates AI-generated SQL before showing it and feeds lint diagnostics back through the same sql-generation transport when correction is needed. If AI-generated SQL still fails after the user manually runs it, Studio sends the failed SQL and database error back through that same transport so the model can propose corrected SQL without auto-running it. All prompting and retry behavior live in Studio itself, so host implementations should stay transport-only.
SQL result visualization uses the shared llm hook with task: "sql-visualization". The host does not need to provide chart components, Chart.js options, callbacks, plugins, or chart-specific APIs. Studio builds the prompt from the executed SQL, database engine, full result rows, and the original AI SQL request when available; the host only forwards that prompt to the model and returns the model text.
Studio validates the model response as a small Bklit chart config before rendering. The response must be strict JSON in this shape:
type SqlResultVisualizationResponse = {
config:
| {
type: "bar" | "horizontal-bar" | "line";
title?: string;
xKey: string;
series: Array<{
key: string;
label?: string;
color?: string;
}>;
stacked?: boolean;
data: Array<Record<string, string | number | boolean | null>>;
}
| {
type: "pie" | "doughnut";
title?: string;
labelKey: string;
valueKey: string;
data: Array<Record<string, string | number | boolean | null>>;
};
};Chart rules:
bar and horizontal-bar require xKey plus one or more numeric series fields.stacked: true is supported only for bar and horizontal-bar.horizontal-bar is preferred for ranked categorical data and long category labels.line requires date-like xKey values: ISO dates, ISO datetimes, or epoch milliseconds.pie and doughnut require labelKey and a numeric valueKey.data rows must contain plain JSON primitive values only.Example stacked horizontal bar response:
{
"config": {
"type": "horizontal-bar",
"title": "Team skills by organization",
"xKey": "organization",
"stacked": true,
"series": [
{ "key": "typescript", "label": "TypeScript" },
{ "key": "postgres", "label": "Postgres" }
],
"data": [
{ "organization": "Acme", "typescript": 4, "postgres": 2 },
{ "organization": "Globex", "typescript": 1, "postgres": 5 }
]
}
}Invalid JSON, unsupported chart types, non-primitive row values, missing keys, non-numeric series values, and non-date line x-values are rejected and fed back to the model for correction. The normative implementation details live in Architecture/sql-result-visualization.md.
Studio is an embeddable React surface, not a standalone app shell. A production integration should:
<Studio /> inside the host product's route, panel, or page@prisma/studio-core/ui/index.css exactly oncecreatePostgresAdapter, createMySQLAdapter, or createSQLiteAdaptercreateStudioBFFClient({ url: "/api/query" })customHeaders and/or customPayloadllm for AI-assisted filtering, SQL generation, SQL result visualization, and Query Insights recommendationsqueryInsights on the adapter when your BFF can return live query snapshotsThe simplest supported shape is: host React app -> <Studio /> -> adapter -> createStudioBFFClient(...) -> host BFF route -> database executor.
Query Insights is an optional Studio feature for embedders that can observe database traffic outside the normal Studio table and SQL views. When enabled, Studio renders a Queries navigation item under the schema visualizer with live query rows, throughput and latency charts, and optional AI recommendations for selected queries.
To enable it:
query-insights procedure described below.bffClient.queryInsights into the adapter as queryInsights.llm hook if you want AI recommendations in query details.const bffClient = createStudioBFFClient({
queryInsights: true,
url: "/api/query",
});
const adapter = createPostgresAdapter({
executor: bffClient,
queryInsights: bffClient.queryInsights,
});If your BFF does not implement query-insights, leave queryInsights false/undefined when creating the BFF client and leave the adapter queryInsights capability undefined. Studio will hide the Queries menu item and stale view=queries URLs will fall back to the normal default view.
What the Queries view renders:
Queries/s and average latency with 1m, 5m, 15m, and 1h rangesLatency, sanitized SQL, Executions, Rows Returned, Last Seen, and optional AnalysisThe chart and table always use the same selected time range. Studio derives visible Executions, Rows Returned, latency, last-seen values, and any provider read-work estimate from the samples it can place inside that range; it does not show cumulative provider counters as if they all happened in the visible window. The first snapshot can still show recent rows as context when their lastSeen timestamp is inside the selected range, but those context rows do not create live throughput values.
Consumer migration notes:
#view=queries. Do not link to #view=query-insights.queryInsights is an adapter capability, not a top-level <Studio /> prop. Enable the BFF bridge with createStudioBFFClient({ queryInsights: true, ... }), then pass bffClient.queryInsights into createPostgresAdapter, createMySQLAdapter, or createSQLiteAdapter alongside the executor.procedure: "query-insights". Studio does not require a Prisma Streams streamUrl; hosts with SSE, pg_stat_statements, ppg.query_stats, proxy logs, or control-plane telemetry should adapt that source into a StudioQueryInsightsSnapshot.llm hook with task: "query-insights". Studio does not expose a separate query-specific analyze() or enableAiRecommendations() transport. Hosts that need consent should enforce it in the llm implementation they pass to Studio.llm request in flight, and stops after the first five automatically discovered query groups. Users can still manually analyze additional rows from the table or detail sheet.Snapshot rows should be aggregated by a stable normalized query identity. Do not send raw parameter values or sensitive payloads; use parameterized SQL or another sanitized query representation. rowsReturned, duration, count, and lastSeen are best-effort operational signals for display and sorting, not accounting-grade telemetry. Studio labels rowsReturned as Rows Returned everywhere in the UI and AI advice. reads is optional provider read-work telemetry for sources that can estimate rows scanned, logical reads, physical reads, or a similar work signal; leave it at `0
No open issues yet, or sync has not completed.