<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: divinesta</title>
    <description>The latest articles on DEV Community by divinesta (@divinesta).</description>
    <link>https://dev.to/divinesta</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1240901%2Fbc3c2244-42e2-4cd6-a6ea-c895662aec9a.png</url>
      <title>DEV Community: divinesta</title>
      <link>https://dev.to/divinesta</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/divinesta"/>
    <language>en</language>
    <item>
      <title>Prisma Studio is not an admin panel</title>
      <dc:creator>divinesta</dc:creator>
      <pubDate>Tue, 18 Aug 2026 21:18:34 +0000</pubDate>
      <link>https://dev.to/divinesta/prisma-studio-is-not-an-admin-panel-4d0m</link>
      <guid>https://dev.to/divinesta/prisma-studio-is-not-an-admin-panel-4d0m</guid>
      <description>&lt;p&gt;If you build with Prisma, you already know Prisma Studio. Run one command and you get a clean, visual way to browse and edit rows in your database. It's genuinely useful, and I reach for it every day while developing.&lt;/p&gt;

&lt;p&gt;But somewhere between "I need to look at my data" and "I need to let a support agent safely edit a customer's record in production," Prisma Studio quietly stops being the right tool. It was never trying to be that tool. It's a database viewer. An admin panel is something else, and the gap between the two is exactly the part that matters once real people and real permissions are involved.&lt;/p&gt;

&lt;p&gt;I ended up building a small package to fill that gap for my own Express + Prisma apps. Writing it forced me to be precise about what an admin panel actually adds on top of a database browser. Here's the distinction as I now understand it.&lt;/p&gt;

&lt;h2&gt;
  
  
  A database browser shows rows. An admin panel governs them.
&lt;/h2&gt;

&lt;p&gt;Prisma Studio connects to your database and shows you everything. That's the point of it, and it's also why you'd never hand it to a non-engineer or expose it in production. It has no concept of &lt;em&gt;who&lt;/em&gt; is looking, &lt;em&gt;what&lt;/em&gt; they're allowed to do, or &lt;em&gt;which&lt;/em&gt; rows they're allowed to touch.&lt;/p&gt;

&lt;p&gt;An admin panel's whole job is those three questions. The package I built mounts a React UI at &lt;code&gt;/admin&lt;/code&gt; and a guarded JSON API under &lt;code&gt;/admin/api/*&lt;/code&gt; on your existing Express app. Every single request through that API runs the same pipeline, in the same order:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;authentication → permission check → tenant scope → validation → Prisma mutation/query → optional audit event&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That ordering is the entire difference. A database browser skips straight to the mutation. An admin panel refuses to run the mutation until it knows the request is authenticated, permitted, scoped to the right tenant, and valid.&lt;/p&gt;

&lt;h2&gt;
  
  
  Permissions and scope are two different questions
&lt;/h2&gt;

&lt;p&gt;This was the design decision I care most about, because collapsing these two into one is how data leaks happen.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Permissions&lt;/strong&gt; decide &lt;em&gt;which actions&lt;/em&gt; a role may take. Can an editor delete a post? Can a support agent create a user?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scope&lt;/strong&gt; decides &lt;em&gt;which rows&lt;/em&gt; a role may see or act on. A support agent for Tenant A should never be able to read, update, or delete Tenant B's records — even for actions they're otherwise fully permitted to perform.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keeping these separate means "you may edit users" and "you may edit &lt;em&gt;these&lt;/em&gt; users" are enforced independently. Scope is applied everywhere it needs to be: lists, single reads, updates, deletes, the choices offered in relation dropdowns, and custom actions. It's the kind of thing that's easy to get 90% right and have the last 10% be a cross-tenant data breach, so the test suite specifically checks that Tenant A cannot view, update, or delete Tenant B's records.&lt;/p&gt;

&lt;p&gt;Prisma Studio has no place to even express this idea. There's no role, so there's nothing to scope.&lt;/p&gt;

&lt;h2&gt;
  
  
  Auth that doesn't touch your users table
&lt;/h2&gt;

&lt;p&gt;Built-in authentication is optional, and when you use it, it deliberately stays out of your application's own data. It uses separate &lt;code&gt;ExpressAdminUser&lt;/code&gt; and &lt;code&gt;ExpressAdminSession&lt;/code&gt; models rather than reading or modifying your app's user and session records. Your admins and your end users are different populations, and mixing them is a recipe for accidents.&lt;/p&gt;

&lt;p&gt;The built-in auth ships with an admin login page, database-backed sessions, a &lt;code&gt;createsuperuser&lt;/code&gt; CLI command, &lt;code&gt;HttpOnly&lt;/code&gt; / &lt;code&gt;SameSite=Lax&lt;/code&gt; cookies, and sign-in throttling. If you already have an auth system you'd rather use, you can bring that instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Audit logging you own
&lt;/h2&gt;

&lt;p&gt;After a successful mutation, the library can emit safe event metadata so you have a record of who changed what. Deliberately, it does not ship its own audit table. You own where those events go and how long they live, because audit storage is a policy decision that belongs to your application, not to a library.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it is &lt;em&gt;not&lt;/em&gt; — and this part is important
&lt;/h2&gt;

&lt;p&gt;I want to be honest about the boundaries, because the fastest way to disappoint someone is to let them think this is something it isn't.&lt;/p&gt;

&lt;p&gt;It is &lt;strong&gt;not a CMS&lt;/strong&gt; and &lt;strong&gt;not a general-purpose internal-tools platform&lt;/strong&gt;. Today, writes support scalar fields plus selecting a single &lt;code&gt;belongsTo&lt;/code&gt; foreign key. That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No nested writes&lt;/li&gt;
&lt;li&gt;No many-to-many editors&lt;/li&gt;
&lt;li&gt;No &lt;code&gt;hasMany&lt;/code&gt; inline tables&lt;/li&gt;
&lt;li&gt;No file uploads&lt;/li&gt;
&lt;li&gt;No rich text or custom widgets&lt;/li&gt;
&lt;li&gt;No exports&lt;/li&gt;
&lt;li&gt;No built-in audit-history UI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It currently supports Prisma 7.5.x only.&lt;/p&gt;

&lt;p&gt;If you need those things, you need a heavier tool, and that's a completely reasonable place to land. What this package does is take the narrow, common, security-sensitive case - schema-driven CRUD that respects permissions and tenant boundaries - and do that part carefully.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one-line version
&lt;/h2&gt;

&lt;p&gt;Prisma Studio answers "what's in my database?" An admin panel answers "who is allowed to change what, and did we record it?" Both are worth having. They're just not the same tool, and reaching for the database browser when you needed the governance layer is a mistake you usually only notice after it's cost you something.``&lt;/p&gt;

</description>
      <category>backend</category>
      <category>database</category>
      <category>prisma</category>
      <category>software</category>
    </item>
  </channel>
</rss>
