<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Untitled Publication]]></title><description><![CDATA[Untitled Publication]]></description><link>https://nadaaa.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Tue, 01 Sep 2026 02:19:53 GMT</lastBuildDate><atom:link href="https://nadaaa.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How I migrated from Supabase to Prisma]]></title><description><![CDATA[In this blog post, I'll share my experience of migrating a project from Supabase to Prisma. My project heavily relied on Supabase for database (DB) management, authentication, row-level security (RLS), and real-time changes.
The main reason for this ...]]></description><link>https://nadaaa.hashnode.dev/how-i-migrated-from-supabase-to-prisma</link><guid isPermaLink="true">https://nadaaa.hashnode.dev/how-i-migrated-from-supabase-to-prisma</guid><category><![CDATA[prisma]]></category><category><![CDATA[supabase]]></category><category><![CDATA[migration]]></category><dc:creator><![CDATA[Nada Farook]]></dc:creator><pubDate>Sun, 03 Mar 2024 09:57:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1709384146223/8af4a8fa-8ca8-4ab1-a80e-d5b66afc8d8d.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this blog post, I'll share my experience of migrating a project from Supabase to Prisma. My project heavily relied on Supabase for database (DB) management, authentication, row-level security (RLS), and real-time changes.</p>
<p>The main reason for this migration was the client's requirement to host the database on AWS and decouple from Supabase.</p>
<p>Additionally, Prisma's ability to switch databases by merely changing the URI string was a main factor.</p>
<p><strong>Understanding Prisma:</strong> Prisma ORM serves as a connector between your application and the database. It ensures that your database remains structured and validates any new changes. Prisma also offers type-safe functions for CRUD operations based on your defined DB schema.</p>
<p><strong>Setup:</strong> The setup process for Prisma was straightforward.</p>
<ol>
<li><p><strong>Initial Configuration:</strong></p>
<ul>
<li><p>Running <code>npx prisma init</code>: This command creates a <code>.env</code> file for adding the DATABASE URL STRING. It also generates a Prisma directory with a <code>schema.prisma</code> file, where you define your database schema.</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1709382425506/61a5b816-15a4-4d36-9bf6-3289adc3f8e7.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
</li>
<li><p><strong>Schema Migration:</strong></p>
<ul>
<li>Since my app's schema was already defined in Supabase, I added my database URL string in the <code>.env</code> file and executed <code>npx prisma db pull</code>. This step automatically pulled the schema from Supabase and translated it into Prisma's format.</li>
</ul>
</li>
</ol>
<p><strong>Understanding Prisma's Basics:</strong> In Prisma, each database table is represented as a 'model'. Within the model, each line represents a table column, specifying its name, data type, and any optional constraints. For an introduction to Prisma's data types and constraints, I recommend this video tutorial: <a target="_blank" href="https://www.youtube.com/watch?v=rLRIB6AF2Dg"><strong>Prisma in 100 Seconds</strong></a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1709382426398/624aa8eb-a6b5-4db0-ac6d-bd0cad95a06d.png" alt class="image--center mx-auto" /></p>
<p><strong>Database Migrations:</strong> Any modifications to the <code>schema.prisma</code> file require updating the changes in the database structure. This is done by running <code>npx prisma migrate</code>. Prisma handles these migrations smoothly and saves all migration files in the Prisma directory under the 'migrations' subdirectory. This feature makes tracking and reverting specific database changes quite efficient.</p>
<p><strong>Generating the Prisma Client:</strong></p>
<ul>
<li><p>To interact with the database for CRUD operations, run <code>npx prisma generate</code>. This command generates a client library with all the type-safe CRUD functions. You can then import this library into your files and access the models using Prisma, benefiting from autocomplete features for model names and column-specific functions.</p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1709382506060/b4211c63-21ed-4155-9a08-2b71f971118f.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
<p><strong>Replacing Supabase with Prisma:</strong> My next step was to replace all functions that used Supabase with the Prisma client. ChatGPT greatly speedup this process, as the basic logic for these functions was already there. For instance, here's how I transformed a function to fetch articles:</p>
<p>Before (Supabase):</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> getArticles = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> supabase = initializeSupabase();
    <span class="hljs-keyword">const</span> { data, error } = <span class="hljs-keyword">await</span> supabase
        .from(<span class="hljs-string">"articles"</span>)
        .select(<span class="hljs-string">"*"</span>)
        .order(<span class="hljs-string">"created_at"</span>, { <span class="hljs-attr">ascending</span>: <span class="hljs-literal">false</span> });

    <span class="hljs-keyword">if</span> (error) {
        <span class="hljs-keyword">throw</span> error;
    }
    <span class="hljs-keyword">return</span> data ?? [];
};
</code></pre>
<p>After (Prisma):</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> getArticles = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> session = <span class="hljs-keyword">await</span> getServerSession(AuthOptions);
    <span class="hljs-keyword">const</span> articles = <span class="hljs-keyword">await</span> prisma.articles.findMany({
        <span class="hljs-attr">where</span>: { <span class="hljs-attr">user_id</span>: session?.user?.id },
        <span class="hljs-attr">orderBy</span>: { <span class="hljs-attr">created_at</span>: <span class="hljs-string">'desc'</span> },
    });
    <span class="hljs-keyword">return</span> articles;
};
</code></pre>
<p><strong>Implementing Authentication:</strong> For authentication, I integrated Next-Auth with an email and password provider, which was quite simple to set up. Next-Auth handles the entire authentication process, including signup/sign-in flows, token, and session management.</p>
<p><strong>Testing:</strong> Finally, I thoroughly tested all the flows and endpoints to ensure everything was functioning correctly.</p>
<p>All the images above are used from <a target="_blank" href="https://www.youtube.com/watch?v=rLRIB6AF2Dg"><strong>Prisma in 100 Seconds</strong></a> by Fireship.</p>
]]></content:encoded></item></channel></rss>