<?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: Russel Dsouza</title>
    <description>The latest articles on DEV Community by Russel Dsouza (@russel_dsouza_bd584a3cb2a).</description>
    <link>https://dev.to/russel_dsouza_bd584a3cb2a</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%2F3939420%2F1d36f555-5b2b-48e8-a97c-2acbb7603dbd.png</url>
      <title>DEV Community: Russel Dsouza</title>
      <link>https://dev.to/russel_dsouza_bd584a3cb2a</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/russel_dsouza_bd584a3cb2a"/>
    <language>en</language>
    <item>
      <title>Best React Native Starter Templates in 2026 (Compared)</title>
      <dc:creator>Russel Dsouza</dc:creator>
      <pubDate>Thu, 06 Aug 2026 11:55:59 +0000</pubDate>
      <link>https://dev.to/russel_dsouza_bd584a3cb2a/best-react-native-starter-templates-in-2026-compared-9he</link>
      <guid>https://dev.to/russel_dsouza_bd584a3cb2a/best-react-native-starter-templates-in-2026-compared-9he</guid>
      <description>&lt;h1&gt;
  
  
  Best React Native Starter Templates in 2026 (Compared)
&lt;/h1&gt;

&lt;p&gt;One of the first questions every React Native developer asks is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"What's the best React Native starter template?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It's a fair question.&lt;/p&gt;

&lt;p&gt;Nobody wants to spend the first week of a project configuring navigation, authentication, theming, folder structure, and dozens of reusable screens before building their actual product.&lt;/p&gt;

&lt;p&gt;A good starter template should help you ship faster—not introduce more decisions.&lt;/p&gt;

&lt;p&gt;After trying several popular React Native starter kits and boilerplates, here are the things that actually matter.&lt;/p&gt;




&lt;h1&gt;
  
  
  What makes a good React Native starter template?
&lt;/h1&gt;

&lt;p&gt;Most comparison articles focus on the tech stack.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Expo vs React Native CLI&lt;/li&gt;
&lt;li&gt;TypeScript&lt;/li&gt;
&lt;li&gt;State management&lt;/li&gt;
&lt;li&gt;Navigation&lt;/li&gt;
&lt;li&gt;Authentication&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those are important, but they're only part of the picture.&lt;/p&gt;

&lt;p&gt;A great starter template should also include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Production-ready screen layouts&lt;/li&gt;
&lt;li&gt;Dark mode support&lt;/li&gt;
&lt;li&gt;Consistent design system&lt;/li&gt;
&lt;li&gt;Reusable components&lt;/li&gt;
&lt;li&gt;Clean project structure&lt;/li&gt;
&lt;li&gt;Easy customization&lt;/li&gt;
&lt;li&gt;Good documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal isn't just to start a project.&lt;/p&gt;

&lt;p&gt;It's to reduce the amount of UI you have to rebuild.&lt;/p&gt;




&lt;h1&gt;
  
  
  What developers usually search for
&lt;/h1&gt;

&lt;p&gt;Most developers aren't actually searching for a "starter template."&lt;/p&gt;

&lt;p&gt;They're trying to solve a specific problem.&lt;/p&gt;

&lt;p&gt;Common searches include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;React Native login screen&lt;/li&gt;
&lt;li&gt;React Native onboarding template&lt;/li&gt;
&lt;li&gt;React Native dashboard UI&lt;/li&gt;
&lt;li&gt;React Native settings screen&lt;/li&gt;
&lt;li&gt;React Native profile screen&lt;/li&gt;
&lt;li&gt;React Native e-commerce UI&lt;/li&gt;
&lt;li&gt;React Native chat UI&lt;/li&gt;
&lt;li&gt;React Native admin dashboard&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your starter template doesn't include these, you'll probably end up building them yourself.&lt;/p&gt;




&lt;h1&gt;
  
  
  Popular React Native starter templates
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Expo Router Starter
&lt;/h2&gt;

&lt;p&gt;Perfect if you want the official Expo experience.&lt;/p&gt;

&lt;p&gt;Pros&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Officially maintained&lt;/li&gt;
&lt;li&gt;Great developer experience&lt;/li&gt;
&lt;li&gt;Excellent documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Minimal UI&lt;/li&gt;
&lt;li&gt;You'll build most application screens yourself&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Ignite
&lt;/h2&gt;

&lt;p&gt;Ignite has been around for years and provides a solid architecture.&lt;/p&gt;

&lt;p&gt;Pros&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Opinionated structure&lt;/li&gt;
&lt;li&gt;State management included&lt;/li&gt;
&lt;li&gt;Great documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Focuses more on architecture than reusable UI.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  React Native Boilerplates
&lt;/h2&gt;

&lt;p&gt;There are dozens of community boilerplates.&lt;/p&gt;

&lt;p&gt;Some are excellent.&lt;/p&gt;

&lt;p&gt;Some haven't been updated in years.&lt;/p&gt;

&lt;p&gt;Before choosing one, always check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Last commit&lt;/li&gt;
&lt;li&gt;Issue activity&lt;/li&gt;
&lt;li&gt;Documentation quality&lt;/li&gt;
&lt;li&gt;React Native version&lt;/li&gt;
&lt;li&gt;Expo compatibility&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  gluestack-ui Pro
&lt;/h2&gt;

&lt;p&gt;Unlike traditional starter templates, &lt;strong&gt;gluestack-ui Pro&lt;/strong&gt; focuses on the part most templates leave out—production-ready app screens.&lt;/p&gt;

&lt;p&gt;Instead of only giving you components, it includes reusable screens for common app flows such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authentication&lt;/li&gt;
&lt;li&gt;Onboarding&lt;/li&gt;
&lt;li&gt;Dashboard&lt;/li&gt;
&lt;li&gt;Settings&lt;/li&gt;
&lt;li&gt;Profile&lt;/li&gt;
&lt;li&gt;Commerce&lt;/li&gt;
&lt;li&gt;Chat&lt;/li&gt;
&lt;li&gt;Wallet&lt;/li&gt;
&lt;li&gt;Media&lt;/li&gt;
&lt;li&gt;Social&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They're built with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Expo 54&lt;/li&gt;
&lt;li&gt;TypeScript&lt;/li&gt;
&lt;li&gt;NativeWind v5&lt;/li&gt;
&lt;li&gt;gluestack-ui v5&lt;/li&gt;
&lt;li&gt;Design tokens&lt;/li&gt;
&lt;li&gt;Light &amp;amp; Dark mode&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://pro.gluestack.io/?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=starter_templates_2026" rel="noopener noreferrer"&gt;Learn more&lt;/a&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  Questions to ask before choosing a starter template
&lt;/h1&gt;

&lt;p&gt;Before adopting any template, ask yourself:&lt;/p&gt;

&lt;p&gt;✅ Can I customize it easily?&lt;/p&gt;

&lt;p&gt;✅ Does it support theming?&lt;/p&gt;

&lt;p&gt;✅ Is the code easy to understand?&lt;/p&gt;

&lt;p&gt;✅ Will it still work after upgrading React Native?&lt;/p&gt;

&lt;p&gt;✅ Does it include the screens I'll end up building anyway?&lt;/p&gt;

&lt;p&gt;These questions matter more than the number of GitHub stars.&lt;/p&gt;




&lt;h1&gt;
  
  
  Final thoughts
&lt;/h1&gt;

&lt;p&gt;The best React Native starter template isn't necessarily the one with the biggest feature list.&lt;/p&gt;

&lt;p&gt;It's the one that removes the most repetitive work.&lt;/p&gt;

&lt;p&gt;Whether that's a lightweight boilerplate, a full architecture starter, or a reusable screen library depends on your workflow.&lt;/p&gt;

&lt;p&gt;If your team repeatedly builds the same authentication flows, dashboards, settings pages, and onboarding experiences, starting with production-ready screens can save days of development on every project.&lt;/p&gt;

&lt;p&gt;What starter template are you using today, and what's the first thing you always end up changing?&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>expo</category>
      <category>mobile</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Gluestack-ui Pro: 55+ Production-Ready React Native Screens</title>
      <dc:creator>Russel Dsouza</dc:creator>
      <pubDate>Wed, 05 Aug 2026 07:30:45 +0000</pubDate>
      <link>https://dev.to/russel_dsouza_bd584a3cb2a/gluestack-ui-pro-55-production-ready-react-native-screens-2b2m</link>
      <guid>https://dev.to/russel_dsouza_bd584a3cb2a/gluestack-ui-pro-55-production-ready-react-native-screens-2b2m</guid>
      <description>&lt;p&gt;Hey everyone!&lt;/p&gt;

&lt;p&gt;If you've ever built a React Native application, you've probably faced this problem. You start a new project, you're excited to build features, solve real user problems, and ship something amazing.&lt;/p&gt;

&lt;p&gt;But before you get there, every application needs the same set of screens.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authentication&lt;/li&gt;
&lt;li&gt;Profile&lt;/li&gt;
&lt;li&gt;Settings&lt;/li&gt;
&lt;li&gt;Chat&lt;/li&gt;
&lt;li&gt;Dashboards&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Almost every project starts with these. The problem isn't that they're difficult to build. The problem is building them well.&lt;/p&gt;

&lt;p&gt;Because this is where users get their first impression of your product. If these screens don't feel polished, the whole application doesn't feel premium. So developers spend hours perfecting layouts, spacing, typography, animations, responsiveness, and design consistency.&lt;/p&gt;

&lt;p&gt;And that's where a lot of development time disappears. Not into building unique features, but into rebuilding the same UI foundation over and over again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing gluestack-ui Pro
&lt;/h2&gt;

&lt;p&gt;That's exactly why we built &lt;a href="https://pro.gluestack.io/?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=gluestack-ui-pro-launch" rel="noopener noreferrer"&gt;gluestack-ui Pro&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Instead of starting every project from scratch, you get a collection of premium, production-ready React Native screens that are ready to integrate into your application. Simply customize them according to your brand, connect your own APIs and business logic, and focus on building the features that make your product unique.&lt;/p&gt;

&lt;h2&gt;
  
  
  55+ Ready-to-use Screens
&lt;/h2&gt;

&lt;p&gt;Right now, it comes with 55+ of the most commonly used React Native screens.&lt;/p&gt;

&lt;p&gt;Whether you're building a startup, an MVP, or a client project, you'll find most of the common screens already available.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv168v2ike0kivaieru96.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv168v2ike0kivaieru96.png" alt=" " width="800" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The layouts are clean. The spacing is consistent. The typography feels polished.&lt;/p&gt;

&lt;p&gt;We've also added smooth animations throughout the application, making the entire experience feel modern and premium. And these aren't just UI mockups. These are real React Native screens that you can integrate directly into your application and customize however you like.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Codebase &amp;amp; Architecture
&lt;/h2&gt;

&lt;p&gt;The codebase is clean and well-structured. The project is easy to navigate, making customization straightforward even for larger applications.&lt;/p&gt;

&lt;p&gt;Design tokens are a big part of that. Instead of hardcoded values scattered throughout the project, everything is driven by tokens.&lt;/p&gt;

&lt;p&gt;So if your designer decides to change the brand color later, you don't have to hunt through dozens of files updating components one by one. Just update the token once, and the changes are reflected across the entire application. The entire styling system is built using Tailwind, which keeps the code clean, readable, and easy to maintain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Modern Tech Stack
&lt;/h2&gt;

&lt;p&gt;gluestack-ui Pro is built with the latest React Native technologies:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Version&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Expo&lt;/td&gt;
&lt;td&gt;54&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NativeWind&lt;/td&gt;
&lt;td&gt;v5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gluestack UI&lt;/td&gt;
&lt;td&gt;v5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Language&lt;/td&gt;
&lt;td&gt;TypeScript&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Seamless Customization
&lt;/h2&gt;

&lt;p&gt;Changing the primary color updates it across the entire application. Same for the background color. One small change updates every screen that uses those design tokens.&lt;/p&gt;

&lt;p&gt;That's the advantage of a proper tokenized design system. You update your design in one place, and the entire application stays consistent.&lt;/p&gt;

&lt;p&gt;There are also several beautifully designed themes included out of the box, and every theme works seamlessly with both Light Mode and Dark Mode.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;One important thing before we wrap up. gluestack-ui Pro isn't trying to replace development. You still own your backend. Your APIs. Your authentication. Your business logic.&lt;/p&gt;

&lt;p&gt;gluestack-ui Pro simply removes the repetitive UI work, giving you a strong foundation so you can focus on building your actual product.&lt;/p&gt;

&lt;p&gt;If you're looking to build React Native applications faster, without spending weeks rebuilding the same UI over and over again, you know where to start. gluestack-ui Pro gives you a production-ready foundation that you can integrate, customize, and make your own.&lt;/p&gt;

&lt;p&gt;Spend less time building common screens, and more time building the features that make your product unique.&lt;/p&gt;

&lt;p&gt;We're launching on Product Hunt today. If any of this is useful to you, a look means a lot.&lt;/p&gt;

&lt;p&gt;What's the screen you rebuild most often? Curious whether it matches ours.&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>expo</category>
      <category>typescript</category>
      <category>ui</category>
    </item>
    <item>
      <title>How tinbase Reimplements Supabase's Wire Protocols in a Single Process (and Runs in a Browser Tab)</title>
      <dc:creator>Russel Dsouza</dc:creator>
      <pubDate>Thu, 30 Jul 2026 07:47:14 +0000</pubDate>
      <link>https://dev.to/russel_dsouza_bd584a3cb2a/how-tinbase-reimplements-supabases-wire-protocols-in-a-single-process-and-runs-in-a-browser-tab-3h9l</link>
      <guid>https://dev.to/russel_dsouza_bd584a3cb2a/how-tinbase-reimplements-supabases-wire-protocols-in-a-single-process-and-runs-in-a-browser-tab-3h9l</guid>
      <description>&lt;p&gt;&lt;em&gt;tinbase is live on Product Hunt today — an open-source, Supabase-compatible backend that runs without Docker. Support the launch here: [&lt;a href="https://www.producthunt.com/products/tinbase" rel="noopener noreferrer"&gt;https://www.producthunt.com/products/tinbase&lt;/a&gt;]&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Local Supabase development means Docker: a 12-container stack and over 2 GB of images to get Postgres, PostgREST, GoTrue, Storage, and Realtime running on a laptop. The platform itself is excellent; the local loop is heavy. And in some environments it isn't just heavy — it's impossible. tinbase was originally built for &lt;a href="https://lifo.sh" rel="noopener noreferrer"&gt;lifo&lt;/a&gt;, a project that maps Linux APIs into the browser, to let Expo apps run fully in-browser with full-stack capability — database, auth, storage, realtime, no server. It's part of the &lt;a href="https://rapidnative.com" rel="noopener noreferrer"&gt;RapidNative&lt;/a&gt; ecosystem, and Docker was never an option in that environment.&lt;/p&gt;

&lt;p&gt;That raised the question: what if the entire Supabase API surface were just a process? One process, embeddable anywhere Node — or a browser tab — runs?&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Supabase compatibility instead of yet another backend
&lt;/h2&gt;

&lt;p&gt;tinbase deliberately avoids inventing another proprietary BaaS API. Supabase's real strength is that it functions as an open standard: PostgREST's REST conventions, GoTrue's auth flows, and a documented realtime protocol, all served by the most widely adopted SDK in the space. Implement those protocols faithfully, and every existing supabase-js app, tutorial, and starter template works with zero changes — and every project stays portable back to hosted Supabase.&lt;/p&gt;

&lt;p&gt;That portability is the design constraint everything else follows from. tinbase reads the same &lt;code&gt;supabase/migrations/*.sql&lt;/code&gt; files and follows the Supabase CLI's migration conventions, tracking them in &lt;code&gt;supabase_migrations.schema_migrations&lt;/code&gt;. It's a different runtime, not a different platform.&lt;/p&gt;

&lt;h2&gt;
  
  
  The architecture
&lt;/h2&gt;

&lt;p&gt;tinbase is a single TypeScript process with three layers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Protocol layer.&lt;/strong&gt; Every service is a pure &lt;code&gt;(Request) =&amp;gt; Response&lt;/code&gt; fetch handler: the PostgREST query grammar (filters, embeds — to-one, to-many, many-to-many via junction, &lt;code&gt;!inner&lt;/code&gt; — JSON paths, upsert, RPC), GoTrue's auth endpoints (email/password, anonymous sign-in, OAuth with PKCE, session refresh with rotation), storage APIs with signed URLs, and realtime speaking the Phoenix protocol over a hand-rolled ~150-line RFC 6455 WebSocket server. Because these are plain fetch handlers rather than a bound HTTP server, they run behind &lt;code&gt;node:http&lt;/code&gt; (or &lt;code&gt;Bun.serve&lt;/code&gt;) on a machine — or get handed to supabase-js as a custom &lt;code&gt;fetch&lt;/code&gt; and invoked directly in-process, with no server at all. That one decision is what makes browser mode possible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Engine adapter layer.&lt;/strong&gt; A thin interface over "a thing that runs Postgres SQL," with three implementations and honest tradeoffs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Embedded native Postgres 17&lt;/strong&gt; — the default on macOS/Linux. First run downloads ~12 MB of platform binaries, then &lt;code&gt;initdb&lt;/code&gt; with memory-lean settings: ~59 MB of RAM at boot, listening only on a private unix socket. Real RLS, triggers, foreign keys, jsonb.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PGlite (wasm)&lt;/strong&gt; — ElectricSQL's Postgres compiled to WASM. Zero setup, runs anywhere Node runs and in the browser, and it's the default on Windows. The tradeoff is memory: its WASM heap sits around 575–650 MB.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;pg-mem&lt;/strong&gt; — a pure-JS in-memory subset at a 3.6 MB install, the lightest option for browser previews. No RLS or cron, but the REST CRUD surface, auth, edge functions, and realtime all work, with change events synthesized in JS by the REST layer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Studio.&lt;/strong&gt; A Supabase-Studio-style dashboard at &lt;code&gt;/_/&lt;/code&gt; — table editor with row CRUD, SQL editor, user management, storage, RLS policies — compiled to a single self-contained HTML file so it works even inside the single binary.&lt;/p&gt;

&lt;h2&gt;
  
  
  The hard parts
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;RLS across engines.&lt;/strong&gt; Every REST and storage request runs inside a transaction with &lt;code&gt;SET LOCAL role&lt;/code&gt; and &lt;code&gt;request.jwt.claims&lt;/code&gt;, so a policy like &lt;code&gt;using (user_id = auth.uid())&lt;/code&gt; behaves identically to hosted Supabase — whether the SQL executes in native Postgres 17 or in WASM.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HTTP without HTTP.&lt;/strong&gt; In a browser tab there is no listener socket. supabase-js expects a URL, so tinbase hands it a custom &lt;code&gt;fetch&lt;/code&gt; that routes requests straight into the protocol handlers in-process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;backend&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;anonKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;global&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;init&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;backend&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;init&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Realtime without WAL.&lt;/strong&gt; Hosted Supabase reads the write-ahead log; tinbase feeds &lt;code&gt;postgres_changes&lt;/code&gt; from triggers plus &lt;code&gt;pg_notify&lt;/code&gt;, and even applies per-subscriber RLS filtering on INSERT/UPDATE events by re-checking the row as that user. (DELETE events can't be re-queried — the row is gone — which is documented as a known gap.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Proving compatibility.&lt;/strong&gt; Claiming "supabase-js works unchanged" is easy; keeping it true is a test-suite problem. 120 tests run the real &lt;code&gt;@supabase/supabase-js&lt;/code&gt; against the backend — REST via in-process fetch, realtime over actual WebSockets, zero mocks — and pass on both the wasm and native engines. Overall coverage lands around 80% of the supabase-js SDK surface, and roughly 90% of what a typical CRUD + auth + storage + realtime app actually calls.&lt;/p&gt;

&lt;h2&gt;
  
  
  The numbers
&lt;/h2&gt;

&lt;p&gt;The footprint benchmark (reproducible via &lt;code&gt;bench/footprint.ts&lt;/code&gt; in the repo) against the same workload — boot, 1,000 inserts, 1,000 filtered reads:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;tinbase (single binary)&lt;/th&gt;
&lt;th&gt;Supabase local&lt;/th&gt;
&lt;th&gt;PocketBase&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Memory at boot&lt;/td&gt;
&lt;td&gt;49 MB&lt;/td&gt;
&lt;td&gt;1,441 MB&lt;/td&gt;
&lt;td&gt;15 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memory after workload&lt;/td&gt;
&lt;td&gt;66 MB&lt;/td&gt;
&lt;td&gt;1,626 MB&lt;/td&gt;
&lt;td&gt;24 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Install size&lt;/td&gt;
&lt;td&gt;92 MB&lt;/td&gt;
&lt;td&gt;2,291 MB&lt;/td&gt;
&lt;td&gt;30 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Processes&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;12 containers + Docker&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;real Postgres 17 + RLS&lt;/td&gt;
&lt;td&gt;Postgres 17&lt;/td&gt;
&lt;td&gt;SQLite&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The honest read: versus Supabase local, ~16–24x less memory and a ~2s boot instead of a minute, with the same SDK and APIs. Versus PocketBase, roughly 2.7x the RAM — but running real Postgres with RLS behind Supabase's exact wire APIs, so code and migrations move to hosted Supabase unchanged.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it looks like in practice
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx tinbase start

&lt;span class="c"&gt;#   API URL: http://127.0.0.1:54321&lt;/span&gt;
&lt;span class="c"&gt;#   anon key: eyJ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@supabase/supabase-js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://127.0.0.1:54321&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ANON_KEY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// everything below this line is unchanged app code&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signUp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;me@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;secret123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;todos&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*, author:users(name)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;done&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or skip the terminal and run the whole backend in a tab: [browser demo link]&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest limits
&lt;/h2&gt;

&lt;p&gt;tinbase is alpha (currently v0.6.x). It's built for local development, prototyping, and embedded/browser use — for production, hosted Supabase remains the recommendation, and a tinbase project migrates there unchanged, which is the point of protocol compatibility. Known gaps are documented in the README: no MFA/SSO/phone auth yet, no resumable (TUS) uploads or image transformations, no pgvector, and the engines currently serialize writes over a single connection — fine for dev tools and small apps, not high-concurrency production. The issue tracker is open and good first issues are labeled.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;GitHub (MIT): &lt;a href="https://github.com/tinbase/tinbase" rel="noopener noreferrer"&gt;https://github.com/tinbase/tinbase&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Live on Product Hunt today: &lt;a href="https://www.producthunt.com/products/tinbase" rel="noopener noreferrer"&gt;https://www.producthunt.com/products/tinbase&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Website: &lt;a href="https://tinbase.dev" rel="noopener noreferrer"&gt;https://tinbase.dev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Built by the team behind &lt;a href="https://rapidnative.com" rel="noopener noreferrer"&gt;RapidNative&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Questions about the protocol reimplementation, the engine adapters, or the fetch-layer trick are welcome in the comments — the team is answering everything today.&lt;/p&gt;

</description>
      <category>supabase</category>
      <category>postgres</category>
      <category>opensource</category>
      <category>webdev</category>
    </item>
    <item>
      <title>React Native Performance Monitoring: Tools and Techniques for 2026</title>
      <dc:creator>Russel Dsouza</dc:creator>
      <pubDate>Tue, 28 Jul 2026 13:42:21 +0000</pubDate>
      <link>https://dev.to/rapidnative-ai/react-native-performance-monitoring-tools-and-techniques-for-2026-dh4</link>
      <guid>https://dev.to/rapidnative-ai/react-native-performance-monitoring-tools-and-techniques-for-2026-dh4</guid>
      <description>&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Flipper is gone&lt;/strong&gt; (removed as default in RN 0.76). React Native DevTools is the sanctioned replacement.&lt;/li&gt;
&lt;li&gt;Track &lt;strong&gt;eight metrics&lt;/strong&gt; — the two most under-monitored are &lt;strong&gt;slow frames %&lt;/strong&gt; and &lt;strong&gt;frozen frames %&lt;/strong&gt;, the closest proxy for "feels laggy."&lt;/li&gt;
&lt;li&gt;The pragmatic 2026 production default: &lt;strong&gt;Sentry&lt;/strong&gt; for crashes + performance, optionally layered with Firebase Crashlytics (free redundancy) or Datadog RUM (if you're already on Datadog).&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;New Architecture&lt;/strong&gt; shifts the culprits: TurboModule calls blocking the JS thread, and Fabric commit contention on the UI thread.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;The React Native performance monitoring landscape looks nothing like it did two years ago. Flipper is gone as the default debugger. The New Architecture — Fabric, TurboModules, and the bridgeless runtime — is on by default in every fresh app. Hermes is the assumed engine.&lt;/p&gt;

&lt;p&gt;If you're shipping in 2026, you need a stack that reflects those changes: dev-time profilers that speak Perfetto and Hermes, production observability that captures slow frames per screen, and a workflow for turning that data into fixes before your App Store rating quietly drops from 4.6 to 4.1.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "performance" actually means in React Native
&lt;/h2&gt;

&lt;p&gt;React Native has a two-thread execution model, and every performance conversation lives inside it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The JS thread&lt;/strong&gt; — business logic, Redux reducers, &lt;code&gt;Animated&lt;/code&gt; orchestration, most third-party code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The UI (main) thread&lt;/strong&gt; — layout, drawing, gesture recognition, native module execution, &lt;code&gt;useNativeDriver&lt;/code&gt; animations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A janky animation is almost always a UI thread problem. A slow list scroll under load is usually a JS thread problem. A screen that takes three seconds to appear after a tap is likely JS thread — &lt;em&gt;unless&lt;/em&gt; it's blocking on a network call, in which case it's a waterfall issue. A frozen screen after login is often a JSI serialization stall.&lt;/p&gt;

&lt;p&gt;Monitoring means tracking both threads, tying the data to specific user journeys, and being able to answer three questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Is it slow?&lt;/strong&gt; — objective metrics on frame rate, TTI, startup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Where is it slow?&lt;/strong&gt; — which screen, component, native module.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why is it slow?&lt;/strong&gt; — flame graphs, network waterfalls, memory pressure.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If your setup only answers question one, you don't have monitoring — you have a smoke alarm.&lt;/p&gt;

&lt;h2&gt;
  
  
  The eight metrics that matter in 2026
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;What it measures&lt;/th&gt;
&lt;th&gt;Healthy target&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;JS FPS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Frame rate on the JS thread&lt;/td&gt;
&lt;td&gt;60 fps sustained (120 on ProMotion)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;UI FPS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Frame rate on the native main thread&lt;/td&gt;
&lt;td&gt;60 fps sustained (120 on ProMotion)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cold start time&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Icon tap to first interactive frame&lt;/td&gt;
&lt;td&gt;&amp;lt; 2.0s on mid-tier Android&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Warm start time&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Time to interactive when backgrounded&lt;/td&gt;
&lt;td&gt;&amp;lt; 400ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;TTI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Screen mount → first tap-responsive frame&lt;/td&gt;
&lt;td&gt;&amp;lt; 1s per screen&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Slow frames %&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Frames rendered in &amp;gt; 16.67ms&lt;/td&gt;
&lt;td&gt;&amp;lt; 5% per session&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Frozen frames %&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Frames rendered in &amp;gt; 700ms&lt;/td&gt;
&lt;td&gt;&amp;lt; 0.1% per session&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;JS bundle size&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Compressed bundle on first launch&lt;/td&gt;
&lt;td&gt;&amp;lt; 2MB gzip&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The two most under-monitored metrics are &lt;strong&gt;slow frames %&lt;/strong&gt; and &lt;strong&gt;frozen frames %&lt;/strong&gt; — the closest proxy for the qualitative "laggy." Sentry, Firebase, and Embrace expose them natively; if your stack doesn't, that's the first upgrade to make.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 2026 tooling stack
&lt;/h2&gt;

&lt;p&gt;Monitoring splits into two phases with different tools: &lt;strong&gt;dev-time profiling&lt;/strong&gt; (finding the problem locally) and &lt;strong&gt;production observability&lt;/strong&gt; (knowing it exists at all).&lt;/p&gt;

&lt;h3&gt;
  
  
  Development-time tools
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;React Native DevTools&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;JS profiling, network, component inspector&lt;/td&gt;
&lt;td&gt;Default since RN 0.76. Replaces Flipper.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Hermes Sampling Profiler&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Deep JS CPU flame graphs&lt;/td&gt;
&lt;td&gt;Export as &lt;code&gt;.cpuprofile&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Perfetto / Systrace&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;System-wide traces across all threads&lt;/td&gt;
&lt;td&gt;Android. Best for bridge/native contention.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Xcode Instruments&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;iOS CPU, memory, energy, Core Animation&lt;/td&gt;
&lt;td&gt;Time Profiler + Animation Hitches.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Android Studio Profiler&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Java/Kotlin allocations, native memory&lt;/td&gt;
&lt;td&gt;Pair with Perfetto.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;React DevTools Profiler&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Render counts, wasted renders&lt;/td&gt;
&lt;td&gt;Ships with RN DevTools.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If a tutorial tells you to install Flipper, it's out of date. Flipper was removed as the default debugger in RN 0.76 and the community plugins are largely unmaintained. React Native DevTools is the replacement, and it's better for JS profiling.&lt;/p&gt;

&lt;h3&gt;
  
  
  Production observability
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;Strengths&lt;/th&gt;
&lt;th&gt;Watch out for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Sentry&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Crash reporting, integrated perf traces, native + JS stack merging&lt;/td&gt;
&lt;td&gt;Sampling costs add up at scale&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Firebase Performance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Free, Crashlytics integration, custom traces&lt;/td&gt;
&lt;td&gt;Sparse UI, no session replay&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Datadog RUM&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Backend APM correlation, cohort analysis&lt;/td&gt;
&lt;td&gt;Expensive at high MAU&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Embrace&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Session-first, full journey replay&lt;/td&gt;
&lt;td&gt;Smaller ecosystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Instabug&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Bug reporting + perf in one SDK&lt;/td&gt;
&lt;td&gt;Duplicates Sentry if you have it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;New Relic Mobile&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Enterprise-grade infra correlation&lt;/td&gt;
&lt;td&gt;Heavier SDK&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The pragmatic default for most teams: &lt;strong&gt;Sentry for crashes + performance + source-mapped traces&lt;/strong&gt;, optionally with &lt;strong&gt;Firebase Crashlytics&lt;/strong&gt; as a free redundant crash pipeline, or &lt;strong&gt;Datadog RUM&lt;/strong&gt; if you're already on Datadog.&lt;/p&gt;

&lt;h2&gt;
  
  
  Minimum-viable production setup
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Install Sentry with performance monitoring.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @sentry/wizard@latest &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; reactNative
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set &lt;code&gt;tracesSampleRate: 0.2&lt;/code&gt; and enable &lt;code&gt;enableNativeFramesTracking: true&lt;/code&gt; and &lt;code&gt;enableAutoPerformanceTracing: true&lt;/code&gt;. Native frames tracking is what gives you slow/frozen frame percentages per screen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Instrument navigation.&lt;/strong&gt; Wrap your app with Sentry's navigation integration so every screen transition becomes a labelled transaction. Without this, traces are anonymous and useless.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Upload source maps on every release.&lt;/strong&gt; Untranslated stack traces are worthless. Bake source map upload into CI so every TestFlight or Play build has readable traces waiting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Add custom spans around slow operations.&lt;/strong&gt; Any function over 100ms — cache hydration, a DB query, a large image decode — gets a manual span. This turns "screen X is slow sometimes" into "screen X is slow because recipe hydration takes 800ms on cold launch."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Set alerts for regressions:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Crash-free session rate below 99.5%&lt;/li&gt;
&lt;li&gt;P75 cold start rising &amp;gt; 20% between releases&lt;/li&gt;
&lt;li&gt;Slow frame % above 8% on any top-10 screen&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A real diagnostic walkthrough: "the feed screen is laggy"
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Confirm in production data
&lt;/h3&gt;

&lt;p&gt;Filter to the screen, look at P75 and P95 of slow frames per session. If P75 is fine and P95 is bad, it's a device-tier issue — likely mid-tier Android under a specific data condition. Note the device and OS distribution of the worst sessions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Reproduce on the right hardware
&lt;/h3&gt;

&lt;p&gt;Never diagnose Android performance on an iPhone 15 Pro. Grab a Pixel 6a or a mid-tier Samsung and reproduce there. Enable the perf overlay for live JS FPS and UI FPS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Capture a trace
&lt;/h3&gt;

&lt;p&gt;For JS-thread issues: React Native DevTools → Performance tab → record the interaction. Look for long JS tasks (&amp;gt; 50ms bars), high re-render counts, serialization work.&lt;/p&gt;

&lt;p&gt;For UI-thread issues on Android: capture a Perfetto trace. Look for main-thread frames overflowing 16.67ms, and whether the overflow is in &lt;code&gt;Choreographer#doFrame&lt;/code&gt; or in native module calls.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Isolate the offender
&lt;/h3&gt;

&lt;p&gt;Common culprits, ranked by frequency in 2026 codebases:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A &lt;code&gt;FlatList&lt;/code&gt; with heavy &lt;code&gt;renderItem&lt;/code&gt; work&lt;/strong&gt; — no memoization, inline arrows. Fix: memoize the row, stabilize props, add &lt;code&gt;getItemLayout&lt;/code&gt; if heights are known.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A large state slice re-rendering the whole tree&lt;/strong&gt; — a selector returning new object identity every time. Fix: narrow the selector, add shallow comparison.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An image decode blocking the UI thread&lt;/strong&gt; — full-res images in small views. Fix: server-side resize, &lt;code&gt;expo-image&lt;/code&gt; with &lt;code&gt;contentFit&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A synchronous &lt;code&gt;AsyncStorage&lt;/code&gt; migration on cold start&lt;/strong&gt; — reading 5MB before render. Fix: defer via &lt;code&gt;InteractionManager.runAfterInteractions&lt;/code&gt;, or MMKV with lazy hydration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A third-party analytics SDK spawning threads on startup&lt;/strong&gt; — 200–400ms blocks. Fix: initialize lazily after first frame.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 5: Verify in a canary
&lt;/h3&gt;

&lt;p&gt;Ship behind a flag or to a beta cohort. Compare P75 slow-frame % on the screen before and after. If the number doesn't move, the fix isn't the fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  The New Architecture changes what you monitor
&lt;/h2&gt;

&lt;p&gt;Under the old bridge, the biggest sinkholes were JSON serialization between JS and native, visible in traces as huge queues. The New Architecture's synchronous, typed JSI calls mostly remove that class of problem — but introduce two new ones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Synchronous TurboModule calls that block the JS thread.&lt;/strong&gt; A native module doing 50ms of I/O now blocks JS directly, where it used to buffer through the async bridge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fabric commit contention on the UI thread.&lt;/strong&gt; Shadow-tree commits are more efficient on average but spike sharply when a large tree diff lands — watch navigation transitions where the whole screen tree re-mounts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Modern Sentry SDKs instrument both Fabric commits and TurboModule calls when auto-performance tracing is on. On an older SDK, upgrade — you'll see spans you didn't have before.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bundle size and startup — the fixes that compound
&lt;/h2&gt;

&lt;p&gt;Startup time is the metric most correlated with day-1 retention, and the one most engineers stop optimizing after the first release.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Enable Hermes.&lt;/strong&gt; If you're not on it, you're leaving 30–50% of cold-start performance on the table.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Precompile Hermes bytecode.&lt;/strong&gt; Ship &lt;code&gt;.hbc&lt;/code&gt;, not &lt;code&gt;.js&lt;/code&gt;. RN does this for release builds — verify it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ship inline requires on Android.&lt;/strong&gt; &lt;code&gt;inlineRequires: true&lt;/code&gt; in Metro defers module evaluation until first use, cutting 200–500ms on large apps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Split third-party SDKs.&lt;/strong&gt; Anything not needed in the first second — analytics, remote config, feature flags — initializes after &lt;code&gt;InteractionManager.runAfterInteractions&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Measure with production RUM, not local.&lt;/strong&gt; Cold start on your dev machine is meaningless. Trust P75 from real devices.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Track JS bundle size release-over-release. A 100KB regression per release compounds fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Best free monitoring tool in 2026?&lt;/strong&gt; Firebase Performance + Crashlytics. Automatic startup and HTTP traces, custom traces, native crash reporting, all free up to a generous tier. Limitations: sparse UI, no session replay — most teams add Sentry for deeper diagnostics.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is Flipper still usable?&lt;/strong&gt; No — removed as default in RN 0.76, plugins unmaintained. Use React Native DevTools, plus Perfetto (Android) and Xcode Instruments (iOS) for native profiling.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I measure startup time in production?&lt;/strong&gt; Sentry's &lt;code&gt;enableAppStartTracking: true&lt;/code&gt;, or Firebase's automatic &lt;code&gt;_app_start&lt;/code&gt; trace. Track &lt;strong&gt;P75 cold start&lt;/strong&gt; — the average hides regressions behind a few fast flagship sessions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What FPS should an app maintain?&lt;/strong&gt; 60 fps sustained on both threads (120 on ProMotion). Track slow frames (&amp;gt; 16.67ms) as a percentage and aim under 5% per session.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do I need separate monitoring for the New Architecture?&lt;/strong&gt; Same metrics, different culprits — TurboModule calls and Fabric commit contention. Any modern SDK instruments both automatically; just don't run a pre-GA-era SDK.&lt;/p&gt;

&lt;h2&gt;
  
  
  The takeaway
&lt;/h2&gt;

&lt;p&gt;The dev-time story is React Native DevTools plus platform-native profilers (Perfetto, Instruments). The production story is Sentry as the default, with Firebase Crashlytics as free redundancy or Datadog RUM for existing Datadog teams.&lt;/p&gt;

&lt;p&gt;The bigger shift is philosophical: performance is a metric you monitor continuously, not a project you do once. The teams shipping the smoothest apps in 2026 have slow-frame alerts wired to Slack, source maps on every release, and a P75 startup dashboard someone actually looks at each Monday.&lt;/p&gt;

&lt;p&gt;I write more about how we handle this in &lt;a href="https://www.rapidnative.com/?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=rn-performance-monitoring" rel="noopener noreferrer"&gt;AI-generated React Native apps at RapidNative&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What's your current monitoring stack — and what's the worst "laggy screen" bug you've tracked down? Mine was a 5MB AsyncStorage migration running on every cold start.&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>performance</category>
      <category>mobile</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Why Supabase local dev needs 2.3 GB of Docker — and how we got it to 58 MB</title>
      <dc:creator>Russel Dsouza</dc:creator>
      <pubDate>Fri, 24 Jul 2026 10:38:36 +0000</pubDate>
      <link>https://dev.to/russel_dsouza_bd584a3cb2a/why-supabase-local-dev-needs-23-gb-of-docker-and-how-we-got-it-to-58-mb-5303</link>
      <guid>https://dev.to/russel_dsouza_bd584a3cb2a/why-supabase-local-dev-needs-23-gb-of-docker-and-how-we-got-it-to-58-mb-5303</guid>
      <description>&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;supabase start&lt;/code&gt; runs the &lt;em&gt;production&lt;/em&gt; architecture on your laptop: 12 containers, &lt;strong&gt;2,291 MB&lt;/strong&gt; on disk, &lt;strong&gt;1,626 MB&lt;/strong&gt; RAM under load&lt;/li&gt;
&lt;li&gt;Those services are mostly protocol translators — and protocols can be reimplemented&lt;/li&gt;
&lt;li&gt;We rebuilt the surface as &lt;strong&gt;one process&lt;/strong&gt;: pure &lt;code&gt;(Request) ⇒ Response&lt;/code&gt; handlers on a swappable Postgres engine&lt;/li&gt;
&lt;li&gt;Result: a &lt;strong&gt;58 MB&lt;/strong&gt; executable, ~2 s cold start, and the official supabase-js SDK passing &lt;strong&gt;168/168&lt;/strong&gt; integration tests unchanged&lt;/li&gt;
&lt;li&gt;Side effect: the same backend runs inside a &lt;strong&gt;browser tab&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Part 1: Where the 2.3 GB goes
&lt;/h2&gt;

&lt;p&gt;Run &lt;code&gt;supabase start&lt;/code&gt; on a fresh machine and watch &lt;code&gt;docker ps&lt;/code&gt; fill up. What you're looking at is Supabase's cloud architecture, faithfully reproduced locally — which is precisely the problem. Each box in their production diagram becomes a container on your laptop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌────────────────────────────────────────────────┐
│  supabase start                                │
│                                                │
│  kong          → API gateway / routing         │
│  postgrest     → REST API over Postgres        │
│  gotrue (auth) → JWTs, OAuth, magic links      │
│  realtime      → WebSockets (Elixir/Phoenix)   │
│  storage-api   → file storage over Postgres    │
│  imgproxy      → image transforms              │
│  edge-runtime  → Deno functions                │
│  studio        → dashboard (Next.js)           │
│  postgres-meta → introspection API for Studio  │
│  logflare      → log aggregation               │
│  vector        → log shipping                  │
│  db (postgres) → the actual database           │
└────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each service ships as its own image with its own runtime — an Elixir VM here, a Deno runtime there, Node for Studio, Go for auth. None of it is waste &lt;em&gt;in production&lt;/em&gt;: these are independently scalable services doing real jobs across a fleet.&lt;/p&gt;

&lt;p&gt;But locally, every one of those runtimes is overhead for a single developer making requests from &lt;code&gt;localhost&lt;/code&gt;. The measured cost:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Install footprint&lt;/th&gt;
&lt;th&gt;Memory under load&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Supabase local (12 containers)&lt;/td&gt;
&lt;td&gt;2,291 MB&lt;/td&gt;
&lt;td&gt;1,626 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tinbase (single binary)&lt;/td&gt;
&lt;td&gt;92 MB&lt;/td&gt;
&lt;td&gt;66 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tinbase (native, via npx)&lt;/td&gt;
&lt;td&gt;36 MB&lt;/td&gt;
&lt;td&gt;100 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;And that's before the Docker Desktop tax on macOS and Windows, or environments where Docker isn't available at all: CI sandboxes, cloud IDEs, school machines, a phone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 2: The key observation — it's protocols all the way down
&lt;/h2&gt;

&lt;p&gt;Here's what makes the whole thing tractable. Your app never talks to those containers directly. It talks to &lt;strong&gt;documented HTTP and WebSocket protocols&lt;/strong&gt; through supabase-js:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/rest/v1&lt;/code&gt; speaks the &lt;strong&gt;PostgREST grammar&lt;/strong&gt; — &lt;code&gt;?select=*,author:users(name)&amp;amp;done=eq.false&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/auth/v1&lt;/code&gt; speaks &lt;strong&gt;GoTrue's API&lt;/strong&gt; — signup, OTP, PKCE, refresh tokens&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/storage/v1&lt;/code&gt; speaks the &lt;strong&gt;Storage API&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Realtime speaks the &lt;strong&gt;Phoenix channel protocol&lt;/strong&gt; over WebSockets&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/functions/v1&lt;/code&gt; invokes edge functions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A protocol doesn't care what implements it. PostgREST is ~"take this URL grammar, compile it to SQL, run it with the caller's JWT claims applied." GoTrue is "manage users in &lt;code&gt;auth.users&lt;/code&gt;, mint JWTs." These are translation layers over Postgres — and translation layers can be reimplemented in-process.&lt;/p&gt;

&lt;p&gt;What you &lt;em&gt;cannot&lt;/em&gt; fake is Postgres itself. RLS evaluation, &lt;code&gt;auth.uid()&lt;/code&gt; in policies, jsonb operators, triggers, &lt;code&gt;ON DELETE CASCADE&lt;/code&gt; — behavior differences there produce the worst kind of bug: works locally, breaks in production. So that became the design rule:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Reimplement the translation layers. Never reimplement Postgres.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Part 3: The architecture — one fetch handler
&lt;/h2&gt;

&lt;p&gt;Every tinbase service is a pure function: &lt;code&gt;(Request) ⇒ Response&lt;/code&gt;. No sockets owned, no ports assumed, no filesystem requirements baked in. The whole backend composes into a single handler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;supabase-js (unmodified)
        │
        ▼
one (Request) ⇒ Response handler
  ├─ /rest/v1      → PostgREST grammar → SQL
  ├─ /auth/v1      → GoTrue flows → auth schema
  ├─ /storage/v1   → Storage API
  ├─ Realtime      → Phoenix protocol
  ├─ /functions/v1 → in-process handlers
  └─ /_/           → Studio dashboard
        │
        ▼
DbEngine adapter
  ├─ native → embedded Postgres 17
  ├─ wasm   → PGlite (Postgres compiled to WASM)
  └─ pg-mem → pure JS, in-memory (subset)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The REST layer parses the PostgREST grammar and compiles it to parameterized SQL — embedded resources become joins, filters become WHERE clauses — then executes with the request's JWT claims set, so your RLS policies run exactly as Postgres intends:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- every request runs with claims applied, e.g.:&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;LOCAL&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;claims&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'{"sub":"&amp;lt;user-uuid&amp;gt;","role":"authenticated"}'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;-- so this policy Just Works, locally and in prod:&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;POLICY&lt;/span&gt; &lt;span class="nv"&gt;"own todos"&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;todos&lt;/span&gt;
  &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;USING&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Realtime does the same per-subscriber: change events are filtered through RLS before delivery, so a user only receives events for rows they're allowed to see.&lt;/p&gt;

&lt;p&gt;Things production Supabase does with Postgres &lt;em&gt;extensions&lt;/em&gt; get reimplemented natively instead, because a single process can just... do them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;database webhooks — no &lt;code&gt;pg_net&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cron.schedule()&lt;/code&gt; — no &lt;code&gt;pg_cron&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;a pgmq subset — no &lt;code&gt;pgmq&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Part 4: The consequences of "pure fetch handler"
&lt;/h2&gt;

&lt;p&gt;This constraint looked academic. It turned out to be the most productive decision in the project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In Node&lt;/strong&gt;, the handler binds to a port and becomes an ordinary HTTP + WebSocket server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx tinbase start
&lt;span class="c"&gt;# ~2 seconds → http://127.0.0.1:54321, Studio at /_/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;As a binary&lt;/strong&gt;, it compiles to a single 58 MB executable — no Node, npm, or Docker on the target machine. That's the CI story: download one file, run it, test against real Postgres.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In a browser&lt;/strong&gt;, you hand the same handler to supabase-js as a custom &lt;code&gt;fetch&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@supabase/supabase-js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createTinbase&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tinbase&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createTinbase&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wasm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;   &lt;span class="c1"&gt;// PGlite under the hood&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://tinbase.local&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ANON_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;global&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fetch&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;   &lt;span class="c1"&gt;// ← the entire backend is this function&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// no server anywhere; Postgres is running inside the tab&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;todos&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello from a browser tab&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Database included, running in-process. No server, no cloud. (Live demo: &lt;a href="https://www.tinbase.dev/browser?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=supabase-local-without-docker" rel="noopener noreferrer"&gt;tinbase.dev/browser&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;We didn't set out to build a curiosity — this was the original requirement. tinbase came out of building &lt;a href="https://rapidnative.com/?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=supabase-local-without-docker" rel="noopener noreferrer"&gt;RapidNative&lt;/a&gt;, where we needed a full dev stack — database, auth, storage, realtime — running in browsers and on phones with no VMs behind it. The single-process backend fell out of that constraint; replacing local Docker was the happy accident.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 5: How we know it's compatible
&lt;/h2&gt;

&lt;p&gt;Claiming "Supabase-compatible" is easy. Our test is blunt: run the &lt;strong&gt;official supabase-js SDK's integration suite&lt;/strong&gt; against tinbase, unmodified.&lt;/p&gt;

&lt;p&gt;Current score: &lt;strong&gt;168/168 passing&lt;/strong&gt;, across both the native Postgres engine and the WASM engine. That covers the REST grammar (filters, embedded resources, RPC), the auth flows (email/password, anonymous, OTP, magic links, recovery, OAuth with PKCE), storage, and realtime's &lt;code&gt;postgres_changes&lt;/code&gt; / broadcast / presence.&lt;/p&gt;

&lt;p&gt;Migration compatibility is the other half. tinbase reads &lt;code&gt;supabase/migrations/*.sql&lt;/code&gt; and &lt;code&gt;seed.sql&lt;/code&gt; exactly like the Supabase CLI, tracked in the same table — so the exit path is: push the same files to hosted Supabase and keep going. Compatibility that doesn't include leaving isn't compatibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this doesn't claim
&lt;/h2&gt;

&lt;p&gt;tinbase is alpha (v0.10.0), and honesty is cheaper than a disappointed issue tracker:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Not production-ready.&lt;/strong&gt; It's for local dev, prototypes, and embedded/browser use.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not 100% of the surface.&lt;/strong&gt; It covers the common paths (the test suite defines "common"); edges remain.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not a Supabase replacement.&lt;/strong&gt; It's the local half of a workflow that ends at hosted Supabase. Real Postgres in production is still the right call.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;pg-mem is a subset.&lt;/strong&gt; The pure-JS engine trades fidelity for zero-WASM environments; use native or PGlite when you can.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try the numbers yourself
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx tinbase start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Repo (MIT): &lt;a href="https://github.com/tinbase/tinbase" rel="noopener noreferrer"&gt;github.com/tinbase/tinbase&lt;/a&gt; — the benchmark methodology is on the site if you want to reproduce the table above.&lt;/p&gt;

&lt;p&gt;If you've solved local-Supabase pain a different way — Nix, compose tricks, &lt;code&gt;pg_regress&lt;/code&gt; heroics — I genuinely want to hear it in the comments. And if you try the browser engine, tell me what you build with it.&lt;/p&gt;

</description>
      <category>supabase</category>
      <category>postgres</category>
      <category>docker</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Introducing tinbase — local Supabase without Docker (one process, real Postgres)</title>
      <dc:creator>Russel Dsouza</dc:creator>
      <pubDate>Thu, 23 Jul 2026 10:04:50 +0000</pubDate>
      <link>https://dev.to/russel_dsouza_bd584a3cb2a/introducing-tinbase-local-supabase-without-docker-one-process-real-postgres-o0b</link>
      <guid>https://dev.to/russel_dsouza_bd584a3cb2a/introducing-tinbase-local-supabase-without-docker-one-process-real-postgres-o0b</guid>
      <description>&lt;ul&gt;
&lt;li&gt;Supabase local dev = a 12-container, &lt;strong&gt;2.3 GB&lt;/strong&gt; Docker stack. tinbase serves the same APIs from &lt;strong&gt;one 58 MB process&lt;/strong&gt;. No Docker.&lt;/li&gt;
&lt;li&gt;It's &lt;strong&gt;real Postgres 17&lt;/strong&gt; — RLS, &lt;code&gt;auth.uid()&lt;/code&gt;, jsonb, triggers, foreign keys all behave like hosted Supabase.&lt;/li&gt;
&lt;li&gt;The official &lt;strong&gt;supabase-js SDK works unchanged&lt;/strong&gt; (168/168 integration tests pass).&lt;/li&gt;
&lt;li&gt;The whole backend — database included — can run &lt;strong&gt;inside a browser tab&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Open source, MIT. Try it: &lt;code&gt;npx tinbase start&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;You know the drill. &lt;code&gt;supabase start&lt;/code&gt;, then Docker pulls Postgres, PostgREST, GoTrue, Storage, Realtime, Studio... twelve containers, 2.3 GB on disk, ~1.6 GB of RAM under load. All you wanted was to run your app locally.&lt;/p&gt;

&lt;p&gt;I love Supabase. I did not love paying a 2 GB tax to write a todo app on the train.&lt;/p&gt;

&lt;h2&gt;
  
  
  What tinbase does instead
&lt;/h2&gt;

&lt;p&gt;One process. Same wire protocols:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Install footprint&lt;/th&gt;
&lt;th&gt;Memory under load&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Supabase local (12 containers)&lt;/td&gt;
&lt;td&gt;2,291 MB&lt;/td&gt;
&lt;td&gt;1,626 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tinbase (single binary)&lt;/td&gt;
&lt;td&gt;92 MB&lt;/td&gt;
&lt;td&gt;66 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tinbase (native)&lt;/td&gt;
&lt;td&gt;36 MB&lt;/td&gt;
&lt;td&gt;100 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx tinbase start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;~2 seconds later you're serving requests. There's also a single 58 MB executable that needs no Node, npm, or Docker on the target machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your code doesn't change
&lt;/h2&gt;

&lt;p&gt;This is the whole point. tinbase implements the PostgREST query grammar, GoTrue auth flows, the Storage API, and the Realtime Phoenix protocol — verified by running the &lt;strong&gt;official SDK&lt;/strong&gt; against it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@supabase/supabase-js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://127.0.0.1:54321&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ANON_KEY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signUp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;todos&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;todos&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*, author:users(name)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;done&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;feed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;postgres_changes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;INSERT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;public&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;table&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;todos&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="nx"&gt;handleNewTodo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No fork of the SDK. No wrapper. No different query language. RLS runs with your JWT claims applied, so &lt;code&gt;auth.uid()&lt;/code&gt; policies work as-is — and Realtime does per-subscriber RLS filtering, so users only get change events for rows they can see.&lt;/p&gt;

&lt;p&gt;Auth covers email/password, anonymous, OTP, magic links, password recovery, and OAuth (Google/GitHub + generic) with PKCE. Edge Functions run in-process via &lt;code&gt;supabase.functions.invoke()&lt;/code&gt;. Webhooks, &lt;code&gt;cron.schedule()&lt;/code&gt;, and a pgmq subset are in there natively — no &lt;code&gt;pg_net&lt;/code&gt;/&lt;code&gt;pg_cron&lt;/code&gt;/&lt;code&gt;pgmq&lt;/code&gt; extensions to install. And a Supabase-Studio-style dashboard ships at &lt;code&gt;/_/&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The weird part: it runs in a browser tab
&lt;/h2&gt;

&lt;p&gt;Every service in tinbase is a pure &lt;code&gt;(Request) ⇒ Response&lt;/code&gt; fetch handler on top of a swappable DB engine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;supabase-js (unmodified)
        │
        ▼
one (Request) ⇒ Response handler
  ├─ /rest/v1      (PostgREST)
  ├─ /auth/v1      (GoTrue)
  ├─ /storage/v1   (Storage)
  ├─ Realtime      (WebSocket)
  ├─ /functions/v1 (Edge Fns)
  └─ /_/           (Studio)
        │
        ▼
DbEngine adapter
  ├─ native  → embedded Postgres 17
  ├─ wasm    → PGlite (Postgres in WASM)
  └─ pg-mem  → pure JS, in-memory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Node, that handler is an HTTP + WebSocket server. In the browser, you hand it to supabase-js as a custom &lt;code&gt;fetch&lt;/code&gt; — and the entire backend, Postgres included, runs in-process in the tab. No server. No cloud. You can play with it at &lt;a href="https://www.tinbase.dev/browser?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=introducing-tinbase" rel="noopener noreferrer"&gt;tinbase.dev/browser&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  It's not a dead end
&lt;/h2&gt;

&lt;p&gt;tinbase reads &lt;code&gt;supabase/migrations/*.sql&lt;/code&gt; and &lt;code&gt;seed.sql&lt;/code&gt; exactly like the Supabase CLI, tracked in the same table. Outgrow it? Push the same files to hosted Supabase and keep moving. You can also point it at a Postgres you already run with &lt;code&gt;--database-url&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why we built it
&lt;/h2&gt;

&lt;p&gt;tinbase came out of building &lt;a href="https://rapidnative.com/?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=introducing-tinbase" rel="noopener noreferrer"&gt;RapidNative&lt;/a&gt; and lifo, with a stubborn goal: run an entire dev stack — database, auth, storage, realtime — in the browser and on phones, with no VMs and no cloud behind it. Cutting the backend down to a single process was step one; making that same process run inside a tab was step two. Somewhere along the way it turned into a genuinely useful Docker-free replacement for local Supabase dev, so we open-sourced the whole thing (MIT).&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest caveats
&lt;/h2&gt;

&lt;p&gt;It's &lt;strong&gt;alpha (v0.10.0)&lt;/strong&gt;. Built for local dev, prototypes, and embedded/browser use — not production. 168/168 integration tests pass across both engines, but if you hit an API edge we haven't covered, open an issue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx tinbase start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GitHub: &lt;a href="https://github.com/tinbase/tinbase" rel="noopener noreferrer"&gt;github.com/tinbase/tinbase&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What would you build if your whole backend fit in a browser tab? Drop a comment — especially if you try the browser engine, I want to see what you make with it. 🚀&lt;/p&gt;

</description>
      <category>supabase</category>
      <category>postgres</category>
      <category>opensource</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Publish Your Lovable App to the App Store (Without Rebuilding It Yourself)</title>
      <dc:creator>Russel Dsouza</dc:creator>
      <pubDate>Wed, 22 Jul 2026 09:43:09 +0000</pubDate>
      <link>https://dev.to/russel_dsouza_bd584a3cb2a/how-to-publish-your-lovable-app-to-the-app-store-without-rebuilding-it-yourself-2jia</link>
      <guid>https://dev.to/russel_dsouza_bd584a3cb2a/how-to-publish-your-lovable-app-to-the-app-store-without-rebuilding-it-yourself-2jia</guid>
      <description>&lt;ul&gt;
&lt;li&gt;Lovable builds a &lt;strong&gt;web app&lt;/strong&gt;. The App Store distributes &lt;strong&gt;native&lt;/strong&gt; apps. That's a category gap, not a skill gap.&lt;/li&gt;
&lt;li&gt;WebView wrappers feel wrong (scroll momentum, transitions, haptics, back gesture) and risk rejection under &lt;strong&gt;App Store Guideline 4.2&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The real fix is a React Native + Expo rebuild — plus certificates, provisioning profiles, signing keys, screenshots, and metadata.&lt;/li&gt;
&lt;li&gt;If your Lovable app uses Supabase, a native rebuild can point at the same project. No migration needed.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;You built something in Lovable over a weekend. It works. You sent the link to friends and they said "wait, you built this?"&lt;/p&gt;

&lt;p&gt;Then someone asked: &lt;em&gt;"Is it on the App Store?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That's where most Lovable projects stall.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why you can't submit a Lovable app to the App Store directly
&lt;/h2&gt;

&lt;p&gt;Building an app and shipping an app are two different projects.&lt;/p&gt;

&lt;p&gt;Lovable is excellent at the first one. But the App Store distributes native apps, and Lovable produces a web app. That's not a skill gap — it's a category gap.&lt;/p&gt;

&lt;p&gt;To publish, you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An Apple Developer account ($99/year)&lt;/li&gt;
&lt;li&gt;A bundle identifier&lt;/li&gt;
&lt;li&gt;A distribution certificate and provisioning profile&lt;/li&gt;
&lt;li&gt;A signed &lt;code&gt;.ipa&lt;/code&gt; binary&lt;/li&gt;
&lt;li&gt;Screenshots at every required device size&lt;/li&gt;
&lt;li&gt;A privacy nutrition label and data-usage disclosure&lt;/li&gt;
&lt;li&gt;A human reviewer who might say no&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of that comes out of a web app builder.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why wrapping it in a WebView doesn't work
&lt;/h2&gt;

&lt;p&gt;The obvious shortcut is a wrapper: put the web app in a native shell and ship the shell. Two problems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It feels wrong.&lt;/strong&gt; Scroll momentum is off. Transitions don't match the platform. Text inputs behave like a browser instead of a native keyboard. No haptics. The back gesture doesn't do what a thumb expects. Users can't name it, but they register it as "website in a box."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Apple notices too.&lt;/strong&gt; Guideline 4.2 exists specifically for repackaged websites that don't provide enough native value. Plenty of wrappers slip through, but you're rolling dice on review — and each rejection costs a full cycle.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a real conversion actually involves
&lt;/h2&gt;

&lt;p&gt;The honest answer is a native rebuild: React Native + Expo, real navigation, real gestures, real device APIs (camera, push, the rest).&lt;/p&gt;

&lt;p&gt;Technically that's the right call. Practically it's where projects die — you spent two days building the product and you're now looking at learning the entire Apple release toolchain, or paying someone who already has.&lt;/p&gt;

&lt;p&gt;That mismatch is the whole problem. The building was fun and fast. The shipping is neither.&lt;/p&gt;

&lt;p&gt;If you'd rather hand that part off, &lt;a href="https://www.rapidnative.com/lovable-to-app-store?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=lovable-to-app-store" rel="noopener noreferrer"&gt;RapidNative converts Lovable apps to React Native and handles the full submission&lt;/a&gt; — signing, screenshots, metadata, the lot. You get a preview build on your device first, the full Expo source code afterward (no lock-in), and rejections are handled at no extra cost until you're approved. Typical turnaround is 1–2 weeks.&lt;/p&gt;

&lt;p&gt;Worth noting for anyone doing this themselves too: &lt;strong&gt;if your Lovable app already talks to Supabase, you don't need to migrate anything.&lt;/strong&gt; Point the React Native app at the same project and your data layer is done.&lt;/p&gt;

&lt;h2&gt;
  
  
  The takeaway
&lt;/h2&gt;

&lt;p&gt;Building and shipping are separate problems. Being good at one tells you nothing about how hard the other will be.&lt;/p&gt;

&lt;p&gt;Lovable made building dramatically easier. Apple's requirements haven't moved — and Google added a 12-tester closed-testing gate on top.&lt;/p&gt;

&lt;p&gt;If your app is stuck one wall away from the store, that's not a verdict on your product. It's just a different category of work than the one you finished.&lt;/p&gt;




&lt;p&gt;Been through App Store submission yourself? Which screen broke you? Mine was the privacy nutrition label.&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>nocode</category>
      <category>ios</category>
      <category>mobile</category>
    </item>
    <item>
      <title>5 Places Sensitive Data Leaks in a React Native App (and How to Plug Them)</title>
      <dc:creator>Russel Dsouza</dc:creator>
      <pubDate>Tue, 21 Jul 2026 07:49:01 +0000</pubDate>
      <link>https://dev.to/rapidnative-ai/5-places-sensitive-data-leaks-in-a-react-native-app-and-how-to-plug-them-3gf1</link>
      <guid>https://dev.to/rapidnative-ai/5-places-sensitive-data-leaks-in-a-react-native-app-and-how-to-plug-them-3gf1</guid>
      <description>&lt;ul&gt;
&lt;li&gt;The leaks that matter usually aren't in production code — they're in the workflow around it.&lt;/li&gt;
&lt;li&gt;Five common ones: &lt;strong&gt;AsyncStorage for tokens&lt;/strong&gt;, &lt;strong&gt;real user data in design mockups&lt;/strong&gt;, &lt;strong&gt;multi-stage AI pipelines&lt;/strong&gt;, &lt;strong&gt;logs and crash reports&lt;/strong&gt;, and &lt;strong&gt;bundled permissions&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Two greps that find real bugs today: &lt;code&gt;AsyncStorage.setItem&lt;/code&gt; near &lt;code&gt;token&lt;/code&gt;, and &lt;code&gt;console.log(user&lt;/code&gt; / &lt;code&gt;console.log(token&lt;/code&gt; / &lt;code&gt;console.log(prompt&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Model consent by &lt;em&gt;purpose&lt;/em&gt;, not by OS permission. Camera consent is not AI-summarization consent.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Data protection posts usually focus on the shipped binary. Encrypt this, pin that certificate, wrap the API client. All correct, all necessary — and all too late if the leak happened three weeks earlier in a design mockup.&lt;/p&gt;

&lt;p&gt;We build AI-generated React Native apps at RapidNative, and the interesting security bugs almost never live in production code. They live in the space between code, design, and AI workflows. Here are five leak points we've watched teams miss.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. AsyncStorage for anything sensitive
&lt;/h2&gt;

&lt;p&gt;The classic. &lt;code&gt;AsyncStorage&lt;/code&gt; is convenient, unencrypted key-value storage. A user session token in AsyncStorage is one rooted device or one iCloud backup extraction away from being replayed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; use &lt;code&gt;expo-secure-store&lt;/code&gt; (Keychain on iOS, Keystore on Android) for anything that unlocks an account.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;SecureStore&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;expo-secure-store&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;saveSessionToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;SecureStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItemAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;session_token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your codebase greps positive for &lt;code&gt;AsyncStorage.setItem&lt;/code&gt; and &lt;code&gt;token&lt;/code&gt;, that's your first PR.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Real user data in design prototypes
&lt;/h2&gt;

&lt;p&gt;A designer opens Figma, needs a realistic list, and pastes 20 rows from the production customer export. Now customer names sit in the design file, which sits in a Figma team folder, which was shared to a contractor's personal email nine months ago.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; a synthetic data script committed to the repo. &lt;code&gt;npx generate-mocks users 20&lt;/code&gt; should be faster than exporting production data. Make the fast path the safe path.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Multi-stage AI workflows
&lt;/h2&gt;

&lt;p&gt;Voice memo lands. Transcription service returns text. A second model extracts tasks. Teammates get pinged.&lt;/p&gt;

&lt;p&gt;That's four handoffs, and the security review probably only covers the API endpoint at step 1.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; draw the pipeline as boxes, list what data each box sees, and confirm each hop has access controls tied to the user's actual consent — not a bundle. Camera consent is not AI-summarization consent.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Logs and crash reports
&lt;/h2&gt;

&lt;p&gt;Sentry, Bugsnag, Datadog, or whatever log aggregator you use sees everything the app hands it. Session tokens in &lt;code&gt;Authorization&lt;/code&gt; headers. AI prompt bodies with user text. Full user IDs in breadcrumbs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; scrub before you send. Most SDKs support a &lt;code&gt;beforeSend&lt;/code&gt; hook.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Sentry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nf"&gt;beforeSend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Grep your codebase for &lt;code&gt;console.log(user&lt;/code&gt;, &lt;code&gt;console.log(token&lt;/code&gt;, and &lt;code&gt;console.log(prompt&lt;/code&gt;. That's your second PR.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Bundled permissions
&lt;/h2&gt;

&lt;p&gt;You ask for camera on onboarding: "we need this for document capture." The user agrees. Six months later a new AI-summarization feature ships that also uses camera frames.&lt;/p&gt;

&lt;p&gt;Same permission, different purpose. Legally shaky (GDPR Article 25 asks for data minimization by design), and practically a betrayal of what the user thought they said yes to.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; model consent as a first-class type, keyed on purpose rather than on OS permission:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ConsentEvent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;granted&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;withdrawn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;policyVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;purpose&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;document-capture&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ai-summary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;marketing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;surface&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;onboarding&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;settings&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;feature-gate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ship a new feature, ask again for that purpose. A one-line inconvenience for the user beats the €7.1B in GDPR fines the EU has issued as of January 2026.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pattern
&lt;/h2&gt;

&lt;p&gt;Notice what the five have in common: none of them are broken TLS, weak crypto, or a mangled JWT signature. They're all &lt;strong&gt;workflow leaks&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Encryption and pinning are table stakes. The bugs that leak your customer's data in 2026 are the ones nobody put in the security review — because they happen in Figma, in a Slack DM, in a Sentry payload, or in an AI pipeline diagram that was never drawn.&lt;/p&gt;

&lt;p&gt;Draw the diagram. Grep the logs. Model consent. Ship.&lt;/p&gt;

&lt;p&gt;Full source with the OWASP and NIST references: &lt;a href="https://rapidnative.com/blogs/data-protection?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=data-protection" rel="noopener noreferrer"&gt;rapidnative.com/blogs/data-protection&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Which of the five would your codebase fail right now? Mine failed #4 the first time I checked.&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>security</category>
      <category>mobile</category>
      <category>webdev</category>
    </item>
    <item>
      <title>You Don't Need 10 Refactoring Tools. Pick 2 From This Decision Tree.</title>
      <dc:creator>Russel Dsouza</dc:creator>
      <pubDate>Tue, 21 Jul 2026 07:35:58 +0000</pubDate>
      <link>https://dev.to/rapidnative-ai/you-dont-need-10-refactoring-tools-pick-2-from-this-decision-tree-2cho</link>
      <guid>https://dev.to/rapidnative-ai/you-dont-need-10-refactoring-tools-pick-2-from-this-decision-tree-2cho</guid>
      <description>&lt;ul&gt;
&lt;li&gt;Answer three questions — &lt;strong&gt;scope of change&lt;/strong&gt;, &lt;strong&gt;how type-heavy your codebase is&lt;/strong&gt;, and &lt;strong&gt;who runs it&lt;/strong&gt; — and the tool choice collapses to two.&lt;/li&gt;
&lt;li&gt;Solo TS-heavy repo: &lt;strong&gt;VS Code + &lt;code&gt;ts-morph&lt;/code&gt;&lt;/strong&gt;. Small team, one repo: &lt;strong&gt;WebStorm + &lt;code&gt;jscodeshift&lt;/code&gt;&lt;/strong&gt;. Multi-repo org: &lt;strong&gt;&lt;code&gt;ast-grep&lt;/code&gt; + Sourcegraph Batch Changes&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;You can skip Babel, Comby, OpenRewrite/Moderne, and ReSharper unless you're in their specific ecosystem.&lt;/li&gt;
&lt;li&gt;Tool sprawl is a symptom: if you're debating 10 tools, the real gap is that nobody's defined what's worth automating.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Every "best refactoring tools" post in 2026 gives you the same 10 names and lets you sort them out.&lt;/p&gt;

&lt;p&gt;But 51% of developers now use AI coding tools daily, and the refactoring-tools market is on track from $1.74B to $5.82B by 2033. That growth means more tools, not clearer choices.&lt;/p&gt;

&lt;p&gt;Here's a smaller frame. Answer three questions, pick two tools, ignore the rest.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 3 questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Scope of the change?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One file, minutes of work: your IDE&lt;/li&gt;
&lt;li&gt;Same rewrite across many files: a codemod&lt;/li&gt;
&lt;li&gt;Same rewrite across many repos: a batch orchestrator&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;How type-heavy is your codebase?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Loose JS or mixed languages: AST / pattern tools&lt;/li&gt;
&lt;li&gt;Strict TypeScript: type-aware transforms&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Who runs it?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Solo: CLI is fine&lt;/li&gt;
&lt;li&gt;Team: you need a shared recipe and review flow&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The 2-tool stacks
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Solo dev, TypeScript-heavy React Native repo.&lt;/strong&gt; Pick VS Code (rename, quick fixes, everyday cleanup) and &lt;code&gt;ts-morph&lt;/code&gt; (type-aware programmable rewrites for the times VS Code's rename gives up). Two tools, both free, both scriptable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Small team, one repo, repetitive structural changes.&lt;/strong&gt; Pick WebStorm (symbol-aware preview so nobody merges a broken rename) and &lt;code&gt;jscodeshift&lt;/code&gt; (AST codemods for the "convert 200 class components to hooks" problem). WebStorm covers day-to-day, jscodeshift covers migrations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multi-repo org, needs consistency.&lt;/strong&gt; Pick &lt;code&gt;ast-grep&lt;/code&gt; (structural search-and-replace fast enough to run in CI) and Sourcegraph Batch Changes (turns a codemod into PRs across every repo). One writes the change, the other ships it everywhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you can skip
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Babel&lt;/strong&gt;, if you're not building a plugin. It's a compiler with a refactoring side-quest, not a refactoring tool.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Comby&lt;/strong&gt;, if your repo is mostly one language. Its edge is cross-language pattern matching.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OpenRewrite and Moderne&lt;/strong&gt;, if you're not on the JVM. Excellent recipes, wrong ecosystem.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JetBrains ReSharper&lt;/strong&gt;, if you're not shipping .NET backends. If you are, you already own it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The real lesson
&lt;/h2&gt;

&lt;p&gt;Tool sprawl is a symptom.&lt;/p&gt;

&lt;p&gt;If your team is debating which of 10 refactoring tools to standardize on, the actual problem is that nobody has defined what kinds of changes are worth automating.&lt;/p&gt;

&lt;p&gt;Pick a scope, pick a scale, pick two tools. Ship a codemod. Learn what breaks. That's the loop.&lt;/p&gt;




&lt;p&gt;If you want the full 10-tool breakdown with when-to-use-each, we wrote it up &lt;a href="https://rapidnative.com/blogs/code-refactoring-tools?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=refactoring-tools-decision-tree" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What's your two-tool stack? Drop it in the comments — curious what people actually settle on.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>productivity</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Prompt-to-App Is a Lie — Here's What Actually Happens</title>
      <dc:creator>Russel Dsouza</dc:creator>
      <pubDate>Wed, 15 Jul 2026 13:02:07 +0000</pubDate>
      <link>https://dev.to/russel_dsouza_bd584a3cb2a/prompt-to-app-is-a-lie-heres-what-actually-happens-3fo5</link>
      <guid>https://dev.to/russel_dsouza_bd584a3cb2a/prompt-to-app-is-a-lie-heres-what-actually-happens-3fo5</guid>
      <description>&lt;p&gt;You type a sentence. Twenty seconds later there's a "React Native app." That's the pitch every prompt-to-app tool ships with in 2026 — Lovable, Bolt, v0, Replit Agent, and the rest. This post is about what actually happens after the demo screen.&lt;/p&gt;

&lt;p&gt;Prompt-to-app tools generate a live-reloading UI in a sandbox against a mocked backend. They do not generate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A real auth system with sessions, password reset, and OAuth&lt;/li&gt;
&lt;li&gt;A database you own with migrations and RLS&lt;/li&gt;
&lt;li&gt;Stripe wiring with real webhooks and Apple IAP handling&lt;/li&gt;
&lt;li&gt;An &lt;code&gt;.ipa&lt;/code&gt; or &lt;code&gt;.aab&lt;/code&gt; you can submit to a store&lt;/li&gt;
&lt;li&gt;The Apple Developer certificate needed to ship&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which is roughly 90% of the actual work.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the demo shows vs. what production needs
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Demo&lt;/th&gt;
&lt;th&gt;Production&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;UI in a web preview&lt;/td&gt;
&lt;td&gt;Signed &lt;code&gt;.ipa&lt;/code&gt; + &lt;code&gt;.aab&lt;/code&gt; submitted to two stores&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mocked API + sample data&lt;/td&gt;
&lt;td&gt;Postgres with migrations, backups, RLS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One screen&lt;/td&gt;
&lt;td&gt;Deep linking, push, background tasks, offline sync&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Preview URL&lt;/td&gt;
&lt;td&gt;Real accounts, OAuth, password reset&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No integrations&lt;/td&gt;
&lt;td&gt;Stripe, IAP, RevenueCat, Sentry, analytics&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No secrets&lt;/td&gt;
&lt;td&gt;Secret storage, key rotation, review notes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The three walls
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Auth.&lt;/strong&gt; The "Sign In" button works in the preview. It doesn't do anything real. Wiring actual OAuth + sessions + RLS is a rewrite of the data layer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Payments.&lt;/strong&gt; On iOS, selling anything digital requires Apple IAP, not Stripe. The tools don't know or care. You'll write this yourself, and it's a two-week job when you factor in webhook handling and license grants.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Submission.&lt;/strong&gt; No agent creates an Apple Developer certificate. No agent captures screenshots at five device sizes. No agent replies to reviewer feedback. This is 30% of any app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the demo works and the app doesn't
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Architecture drift.&lt;/strong&gt; &lt;a href="https://seismicpixels.com/ai-coding-hype-vs-reality/" rel="noopener noreferrer"&gt;AI-heavy codebases show 39% higher code churn&lt;/a&gt; — code reverted or heavily rewritten within two weeks. LLMs have no persistent memory of the constraints they set twenty prompts ago. They redefine &lt;code&gt;User&lt;/code&gt; in three files.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hidden state.&lt;/strong&gt; The "backend" is a black-box datastore the tool provisions. You can't run migrations. You can't add a trigger. You can't set up &lt;a href="https://supabase.com/docs/guides/database/postgres/row-level-security" rel="noopener noreferrer"&gt;Supabase-style RLS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stack lock-in.&lt;/strong&gt; Most tools are aggressively opinionated. v0 outputs React + Tailwind. If you need Expo, native modules, or actual app store distribution, you're outside the happy path.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No distribution story.&lt;/strong&gt; &lt;a href="https://docs.expo.dev/submit/introduction/" rel="noopener noreferrer"&gt;Docs for &lt;code&gt;eas submit&lt;/code&gt;&lt;/a&gt; exist because submission is a real, human-mediated process. No prompt generates it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The workflow that actually ships
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Start from a template that owns the boring stuff&lt;/span&gt;
git clone &amp;lt;template-repo&amp;gt; my-app
&lt;span class="nb"&gt;cd &lt;/span&gt;my-app
bun &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="c"&gt;# 2. Point your agent at the repo&lt;/span&gt;
&lt;span class="c"&gt;# Claude Code, Codex, Cursor, whatever&lt;/span&gt;
&lt;span class="c"&gt;# Templates ship with .claude/skills/ so the agent knows the conventions&lt;/span&gt;

&lt;span class="c"&gt;# 3. Extend, don't invent&lt;/span&gt;
&lt;span class="c"&gt;# "Add a photo upload feature to the events screen"&lt;/span&gt;
&lt;span class="c"&gt;# "Wire the settings screen to the existing Stripe customer portal"&lt;/span&gt;

&lt;span class="c"&gt;# 4. Ship&lt;/span&gt;
eas build &lt;span class="nt"&gt;--platform&lt;/span&gt; all
eas submit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent is in this workflow. It just isn't inventing the architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  The split that works
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// The template owns things like this:&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/lib/supabase&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;requireAuth&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/lib/auth&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;uploadNote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;blob&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Blob&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;requireAuth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;notes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;blob&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// The agent adds features on top:&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;shareNoteAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;noteId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;note&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getNote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;noteId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pdf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;renderPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;uploadNote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The template's &lt;code&gt;supabase&lt;/code&gt;, &lt;code&gt;requireAuth&lt;/code&gt;, and &lt;code&gt;storage.from("notes")&lt;/code&gt; are load-bearing infrastructure. They already work. They already have RLS. The agent's job is the last function, not the first three.&lt;/p&gt;

&lt;h2&gt;
  
  
  When prompt-to-app is actually fine
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Marketing pages and landing sites (v0 is great for this)&lt;/li&gt;
&lt;li&gt;Prototypes for design review&lt;/li&gt;
&lt;li&gt;One-off internal tools without auth or payments&lt;/li&gt;
&lt;li&gt;Learning what components look like&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Prompt-to-app is a rendering technology. It's not a shipping technology. Use it for what it's good at.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q: Are prompt-to-app tools useless?&lt;/strong&gt;&lt;br&gt;
No. Great for prototypes and marketing pages. Poor fit for shipping real mobile apps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Won't they get better?&lt;/strong&gt;&lt;br&gt;
Some of it, over years. Code signing and App Store review aren't things LLMs prompt their way through. Bet on agents inside real projects, not agents inventing them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: What stack should I pick?&lt;/strong&gt;&lt;br&gt;
Expo, TypeScript, Supabase, NativeWind, Stripe (+ Apple IAP for digital goods). Boring, well-documented, agent-friendly.&lt;/p&gt;




&lt;p&gt;I keep a set of Expo + Supabase templates wired for exactly this workflow at &lt;a href="https://www.applighter.com/apps?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=prompt-to-app-is-a-lie" rel="noopener noreferrer"&gt;Applighter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What's the wall that cost you the most time — auth, payments, or submission? Drop it in the comments.&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>expo</category>
      <category>supabase</category>
      <category>ai</category>
    </item>
    <item>
      <title>AI Coding Agents Need a Foundation, Not a Canvas</title>
      <dc:creator>Russel Dsouza</dc:creator>
      <pubDate>Wed, 01 Jul 2026 13:10:48 +0000</pubDate>
      <link>https://dev.to/russel_dsouza_bd584a3cb2a/ai-coding-agents-need-a-foundation-not-a-canvas-2j1e</link>
      <guid>https://dev.to/russel_dsouza_bd584a3cb2a/ai-coding-agents-need-a-foundation-not-a-canvas-2j1e</guid>
      <description>&lt;ul&gt;
&lt;li&gt;Same prompt, two repos: &lt;strong&gt;blank Expo repo → 47min / $5.20 / un-mergeable&lt;/strong&gt;; wired foundation → &lt;strong&gt;11min / $0.85 / mergeable&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The model didn't get smarter. The repo got more legible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AGENTS.md helps ~4% (hand-written) or hurts 2–3% (LLM-generated), per a 138-repo / 5,694-PR study&lt;/strong&gt;. Both add &amp;gt;20% to token cost. It's not the fix.&lt;/li&gt;
&lt;li&gt;A real foundation ships &lt;strong&gt;one visible convention per cross-cutting concern&lt;/strong&gt;, typed boundaries, one way to do each thing, pre-installed skills, and a working end-to-end path.&lt;/li&gt;
&lt;li&gt;The evaluation heuristic: &lt;strong&gt;"Open the repo and ask Claude Code to add a screen. If the first thing the agent does is install three packages, the foundation is decorative."&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Cold open
&lt;/h2&gt;

&lt;p&gt;I had a working theory that the gap between coding agents that "feel useful" and coding agents that "feel like a coworker" was a model gap. Smarter base model, better tool use, longer context window. The usual story.&lt;/p&gt;

&lt;p&gt;Then I ran the same prompt against two different repos and the theory died on contact.&lt;/p&gt;

&lt;p&gt;The prompt was: &lt;em&gt;"Add a weekly summary screen that fetches the last seven days of data from Supabase and renders a bar chart."&lt;/em&gt; Mid-tier feature, nothing exotic. I ran it against a fresh &lt;code&gt;npx create-expo-app&lt;/code&gt; and against a fully wired React Native / Expo / Supabase foundation.&lt;/p&gt;

&lt;p&gt;Same model. Same prompt. Two completely different sessions.&lt;/p&gt;

&lt;p&gt;On the blank repo, the agent installed three chart libraries, picked one, then quietly imported a different one in the second file it wrote. It hardcoded the Supabase URL. It invented an &lt;code&gt;api/&lt;/code&gt; folder, then later invented a &lt;code&gt;services/&lt;/code&gt; folder, then never used either. After 47 minutes and roughly $5.20 in tokens, it produced 600 lines of code I would not merge into anything.&lt;/p&gt;

&lt;p&gt;On the foundation, the agent did something that, at first, felt anticlimactic. It opened one existing screen, read it, and then wrote one new screen that looked exactly like the existing one. Same chart primitive. Same data fetcher. Same file structure. 11 minutes. About 85 cents in tokens. Mergeable on the first read.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The model hadn't gotten smarter. The repo had gotten more legible.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The blank-canvas problem, named
&lt;/h2&gt;

&lt;p&gt;Every coding agent — Claude Code, Cursor, Codex, Windsurf, the lot — is doing roughly the same thing under the hood. It reads the repo, then writes code that "fits." When the repo has shape, "fits" means matching the shape. When the repo has no shape, "fits" means matching the median of the public internet.&lt;/p&gt;

&lt;p&gt;The public internet is a thousand React Native tutorials, each of which makes different micro-decisions. State library: Redux, Zustand, Jotai, Recoil, Context. Data fetching: TanStack Query, SWR, raw fetch, Supabase client wrappers. Navigation: Expo Router, React Navigation, stack vs. tabs vs. drawer. Theming: NativeWind, styled-components, StyleSheet, restyle. The "median" picks one of each, often differently per file.&lt;/p&gt;

&lt;p&gt;This is the blank-canvas problem. The agent does not fail because it is dumb. It fails because every choice is open and the choices don't compose.&lt;/p&gt;

&lt;h2&gt;
  
  
  The AGENTS.md cul-de-sac
&lt;/h2&gt;

&lt;p&gt;The current industry answer is &lt;code&gt;AGENTS.md&lt;/code&gt; — a Markdown file at the root of the repo describing your conventions. I have written several. They help, in the way that a sticky note on the fridge helps. They do not solve the problem.&lt;/p&gt;

&lt;p&gt;The numbers are unkind. A study earlier this year analyzed &lt;code&gt;AGENTS.md&lt;/code&gt; impact across 138 repositories and 5,694 pull requests. The headline:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;LLM-generated &lt;code&gt;AGENTS.md&lt;/code&gt; files &lt;strong&gt;hurt&lt;/strong&gt; agent performance by 2–3%.&lt;/li&gt;
&lt;li&gt;Hand-written &lt;code&gt;AGENTS.md&lt;/code&gt; files improved performance by &lt;strong&gt;4%&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Both raised token costs by &lt;strong&gt;20%+&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;4% is not the breakthrough you were hoping for. It's noise.&lt;/p&gt;

&lt;p&gt;The intuition behind why is straightforward once you sit with it: prose about code is a weaker signal than code itself. An agent that reads three screens which all use the same data fetcher infers, very confidently, that the fourth screen should use the same fetcher. An agent that reads a sentence in &lt;code&gt;AGENTS.md&lt;/code&gt; saying "use the data fetcher in &lt;code&gt;lib/&lt;/code&gt;" sometimes does, sometimes doesn't.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The pattern is the prior. The &lt;code&gt;AGENTS.md&lt;/code&gt; is a cache.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What an actual agent-ready foundation contains
&lt;/h2&gt;

&lt;p&gt;The phrase "agent-ready" is doing a lot of work in boilerplate marketing. Here is what it should mean, concretely:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Visible conventions
&lt;/h3&gt;

&lt;p&gt;Every cross-cutting concern — auth, data fetching, navigation, theming, state, payments, push — appears in at least one fully wired screen. The agent has a working example to copy. Not three contradictory examples. Not one half-finished example. One canonical example.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Typed boundaries
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Supabase generated types — the agent cannot fake its way past these&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Database&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;public&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;Tables&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;daily_summaries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="nl"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="nl"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="nl"&gt;total_calories&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="c1"&gt;// ...&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="nl"&gt;Insert&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="nl"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the agent calls a column that doesn't exist, &lt;code&gt;tsc&lt;/code&gt; fails. The foundation makes the type system enforce the prior.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. One way to do each thing
&lt;/h3&gt;

&lt;p&gt;If your foundation has both Redux and Zustand, the agent will use both. If it has only Zustand, the agent will use Zustand. Foundations make choices the agent doesn't have to.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Pre-installed skills and slash commands
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.claude/skills/
  add-screen.md           — knows where screens go, how they're wired
  wire-supabase-rpc.md    — knows how RPCs are exposed
  add-stripe-product.md   — knows the webhook layout
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A skill is a scoped operation the agent can invoke directly. It is not prompt engineering. It is the foundation describing what it lets you do.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. A working end-to-end path
&lt;/h3&gt;

&lt;p&gt;Auth → database read → typed UI → push notification, all wired up once. The agent reads the whole chain in a single context window and now has a template for every future feature that touches the chain.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a real foundation looks like on disk
&lt;/h2&gt;

&lt;p&gt;Here's what a real React Native + Expo + Supabase foundation looks like when an agent opens it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;your-app/
├── app/                        # Expo Router screens
│   ├── (tabs)/
│   │   ├── index.tsx           # Home + today's entries
│   │   ├── add.tsx             # Camera + analysis flow
│   │   └── stats.tsx           # Daily summary chart
│   └── auth/
│       └── login.tsx           # OAuth + email + Apple
├── modules/
│   ├── db/
│   │   ├── supabaseClient.ts
│   │   └── supabaseServer.ts
│   ├── auth/
│   │   └── useAuth.ts
│   └── vision/
│       └── analyzeFood.ts      # Vision API integration
├── supabase/
│   └── migrations/             # Real, dated, ordered migrations
├── components/                 # NativeWind primitives
└── .claude/
    └── skills/                 # Scoped agent operations
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the agent opens this and you ask for a weekly-summary feature, it reads &lt;code&gt;stats.tsx&lt;/code&gt;, reuses the chart primitive in &lt;code&gt;components/&lt;/code&gt;, calls the same &lt;code&gt;supabaseServer&lt;/code&gt; client, drops the screen in &lt;code&gt;(tabs)/&lt;/code&gt;, and follows the same migration pattern if it needs a new column.&lt;/p&gt;

&lt;p&gt;The agent never asks "what state library should I use?" because the repo answered the question.&lt;/p&gt;

&lt;h2&gt;
  
  
  The economics, in detail
&lt;/h2&gt;

&lt;p&gt;I tracked twelve sessions across three teammates — six from blank repos, six from foundations — using the same model and same prompt categories. Averages:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Blank repo&lt;/th&gt;
&lt;th&gt;Foundation&lt;/th&gt;
&lt;th&gt;Delta&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Tokens per shipped feature&lt;/td&gt;
&lt;td&gt;$4.30&lt;/td&gt;
&lt;td&gt;$0.95&lt;/td&gt;
&lt;td&gt;4.5× cheaper&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wall time per feature&lt;/td&gt;
&lt;td&gt;42 min&lt;/td&gt;
&lt;td&gt;9 min&lt;/td&gt;
&lt;td&gt;4.7× faster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Diffs requiring full rewrite&lt;/td&gt;
&lt;td&gt;4 of 6&lt;/td&gt;
&lt;td&gt;0 of 6&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hallucinated imports&lt;/td&gt;
&lt;td&gt;11 total&lt;/td&gt;
&lt;td&gt;1 total&lt;/td&gt;
&lt;td&gt;11× fewer&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This is not a controlled study. It is, however, consistent with what teammates and customers report. The gap is real and it is wide.&lt;/p&gt;

&lt;p&gt;If you ship one app a year, the gap doesn't matter much — you'll spend a month either way. If you ship three or four, the gap is the difference between "we can" and "we can't."&lt;/p&gt;

&lt;h2&gt;
  
  
  What this does not mean
&lt;/h2&gt;

&lt;p&gt;Two clarifications, because the foundation argument gets oversold.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A foundation does not replace judgment.&lt;/strong&gt; The agent still ships things you have to review. The foundation just narrows what the agent can ship.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A foundation is not forever.&lt;/strong&gt; Two years from now the model will be stronger, the framework will have shifted, and today's foundation will feel constraining. Throw it away when it does. Until then, it earns its keep every session.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to evaluate any foundation you're considering
&lt;/h2&gt;

&lt;p&gt;Whether you're considering a paid template, a free GitHub template, or something a friend shipped — the test is the same:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Open the repo and ask Claude Code to add a screen. If the first thing the agent does is install three packages, the foundation is decorative.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Other tests, in order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Count real screens.&lt;/strong&gt; Five or more, all using the same conventions, is the bar.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Grep for &lt;code&gt;any&lt;/code&gt;.&lt;/strong&gt; If the data layer leaks &lt;code&gt;any&lt;/code&gt;, the agent has no priors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Find the skills directory.&lt;/strong&gt; No skills, no scoped operations, the foundation is half-built.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read the migrations folder.&lt;/strong&gt; Real, dated migrations are a foundation signal. A single &lt;code&gt;init.sql&lt;/code&gt; is a boilerplate signal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run the first session.&lt;/strong&gt; Token cost and wall-clock time will tell you everything within 15 minutes.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is a foundation just a fancy boilerplate?&lt;/strong&gt;&lt;br&gt;
No. A boilerplate is the packaging. A foundation is the wiring. Most boilerplates are not foundations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why doesn't a great AGENTS.md fix this?&lt;/strong&gt;&lt;br&gt;
It helps about 4%, per the 138-repo study. The pattern is a much stronger prior than prose about the pattern.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does this only apply to React Native?&lt;/strong&gt;&lt;br&gt;
No. It applies to every stack. React Native is the worst case because its ecosystem is the most fragmented, so the gap is largest there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should I buy or build the foundation?&lt;/strong&gt;&lt;br&gt;
Build if you'll ship three or more apps on the same stack. Buy if this is your first or second.&lt;/p&gt;




&lt;p&gt;If you take one thing away: do not hand an AI coding agent an empty room and ask it to build a house. Give it a foundation. Then ask it to add the rooms.&lt;/p&gt;

&lt;p&gt;For the longer breakdown — including the specific "one way to do each thing" heuristics I use to audit a foundation — see &lt;a href="https://www.applighter.com/blog?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=ai-coding-agent-needs-foundation-2026" rel="noopener noreferrer"&gt;the Applighter blog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What's the weirdest thing an AI coding agent has done in your blank repo? Drop it in the comments — I'm collecting the failure modes for a follow-up. (Bonus points for a token-cost screenshot.)&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>expo</category>
      <category>supabase</category>
      <category>ai</category>
    </item>
    <item>
      <title>Buy a React Native Template or Build From Scratch in 2026?</title>
      <dc:creator>Russel Dsouza</dc:creator>
      <pubDate>Tue, 30 Jun 2026 09:59:09 +0000</pubDate>
      <link>https://dev.to/russel_dsouza_bd584a3cb2a/buy-a-react-native-template-or-build-from-scratch-in-2026-j93</link>
      <guid>https://dev.to/russel_dsouza_bd584a3cb2a/buy-a-react-native-template-or-build-from-scratch-in-2026-j93</guid>
      <description>&lt;p&gt;You've run &lt;code&gt;npx create-expo-app&lt;/code&gt;, and three days later you're configuring NativeWind v4 PostCSS, debugging Supabase deep-link callbacks, and writing your fifth token-refresh &lt;code&gt;useEffect&lt;/code&gt;. The decision hits: keep grinding, or buy a $79 React Native template and skip to the actual product?&lt;/p&gt;

&lt;p&gt;This post is a decision framework with the actual numbers. No marketing — the math leans toward buying, and the rest of this post explains exactly when it doesn't.&lt;/p&gt;

&lt;p&gt;Buy when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The app is a recognizable pattern (auth + DB + payments + a vertical UI)&lt;/li&gt;
&lt;li&gt;You're solo or a two-person team&lt;/li&gt;
&lt;li&gt;Your time is worth more than $50/hour&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Build from scratch when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The UX is genuinely novel&lt;/li&gt;
&lt;li&gt;You have hard compliance (HIPAA, PCI L1, SOC 2)&lt;/li&gt;
&lt;li&gt;You're learning React Native and the setup is the point&lt;/li&gt;
&lt;li&gt;You're at 1M+ user scale on day one&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The setup tax
&lt;/h2&gt;

&lt;p&gt;Foundation work, before any product code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Expo + TS + ESLint + Prettier ......... 4h
Expo Router v4 (typed routes) ......... 6h
Supabase auth (email/Apple/Google) .... 14h
NativeWind v4 + dark mode ............. 8h
TanStack Query + Zustand .............. 6h
Stripe / RevenueCat ................... 16h
Push (APNs + FCM via Expo) ............ 8h
Supabase Storage + RLS ................ 6h
Sentry + PostHog ...................... 4h
EAS Build + iOS/Android signing ....... 8h
─────────────────────────────────────────
Total .................................. ~80h
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At $75/hr indie rate that's &lt;strong&gt;$6,000 of your time&lt;/strong&gt;. At $150/hr US contract, $12,000. Most of those hours are commodity work — you are not building a moat, you are configuring &lt;code&gt;app.json&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Template price tiers in 2026
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$0–29     screen kits, free boilerplates (no backend, stale fast)
$49–99    full-stack with real backend (Supabase/Firebase/Node)
$199–499  vertical clones (food delivery, marketplace, dating)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a $79 template saves 60 of those 80 hours, the effective hourly rate for from-scratch to win is under $1.32/hour. Don't be that cheap.&lt;/p&gt;

&lt;h2&gt;
  
  
  Buy vs. build at a glance
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Factor&lt;/th&gt;
&lt;th&gt;Build&lt;/th&gt;
&lt;th&gt;Buy&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Time to deployable build&lt;/td&gt;
&lt;td&gt;3–6 weeks&lt;/td&gt;
&lt;td&gt;1–2 days&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cash cost&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;td&gt;$49–499&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Time cost&lt;/td&gt;
&lt;td&gt;80–200h&lt;/td&gt;
&lt;td&gt;2–8h customization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Code understood day 1&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;60–80% (100% after a week)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Architecture quality&lt;/td&gt;
&lt;td&gt;Your choices&lt;/td&gt;
&lt;td&gt;Template's choices&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security posture&lt;/td&gt;
&lt;td&gt;What you remember&lt;/td&gt;
&lt;td&gt;What was shipped&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best for&lt;/td&gt;
&lt;td&gt;Novel UX, learning, compliance&lt;/td&gt;
&lt;td&gt;MVPs, vertical clones, agency work&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The buyer's checklist
&lt;/h2&gt;

&lt;p&gt;Before you buy, verify:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Is the backend real or mocked?&lt;/span&gt;
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s2"&gt;"mockApi&lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="s2"&gt;fixtures"&lt;/span&gt; src/

&lt;span class="c"&gt;# 2. React Native + Expo version&lt;/span&gt;
&lt;span class="nb"&gt;cat &lt;/span&gt;package.json | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s2"&gt;"react-native|expo"&lt;/span&gt;
&lt;span class="c"&gt;# Floor in 2026: RN 0.81, Expo SDK 54&lt;/span&gt;

&lt;span class="c"&gt;# 3. Leaked keys&lt;/span&gt;
git log &lt;span class="nt"&gt;-p&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-iE&lt;/span&gt; &lt;span class="s2"&gt;"sk_live|service_role|AKIA"&lt;/span&gt;

&lt;span class="c"&gt;# 4. TypeScript strict mode&lt;/span&gt;
&lt;span class="nb"&gt;cat &lt;/span&gt;tsconfig.json | &lt;span class="nb"&gt;grep &lt;/span&gt;strict

&lt;span class="c"&gt;# 5. Last commit recency&lt;/span&gt;
git log &lt;span class="nt"&gt;-1&lt;/span&gt; &lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;%cd

&lt;span class="c"&gt;# 6. License terms&lt;/span&gt;
&lt;span class="nb"&gt;cat &lt;/span&gt;LICENSE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a template fails on (1) — backend is mocked — you don't have a template, you have a screen kit. You will rebuild the entire backend.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "production-ready" should actually mean
&lt;/h2&gt;

&lt;p&gt;Six bars a template should clear before it can use the phrase:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A Postgres schema with RLS you can &lt;code&gt;supabase db push&lt;/code&gt; — see &lt;a href="https://supabase.com/docs/guides/auth/row-level-security" rel="noopener noreferrer"&gt;Supabase RLS docs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Auth flows that pass App Store review (Apple Sign-In mandatory if any other social)&lt;/li&gt;
&lt;li&gt;Server routes for anything sensitive (no API keys on device)&lt;/li&gt;
&lt;li&gt;Error / loading / empty states wired everywhere&lt;/li&gt;
&lt;li&gt;EAS Build profiles producing signed iOS + Android binaries — see &lt;a href="https://docs.expo.dev/build/introduction/" rel="noopener noreferrer"&gt;EAS Build docs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;AI agents (Claude Code, Cursor) can extend it without breaking the architecture&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The sixth is the 2026 bar that didn't exist in 2023. AI agents do their best work on known-good repos. Templates that confuse agents lose to ones that don't.&lt;/p&gt;

&lt;h2&gt;
  
  
  When buying wins
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Your app is "X for Y" where both X and Y already exist&lt;/li&gt;
&lt;li&gt;Solo / two-person team&lt;/li&gt;
&lt;li&gt;Agency / contractor billing a client (license permitting)&lt;/li&gt;
&lt;li&gt;You want a security baseline you didn't write at 1 AM&lt;/li&gt;
&lt;li&gt;You're driving development with AI agents&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When building wins
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Novel UX with no obvious analog&lt;/li&gt;
&lt;li&gt;Hard compliance constraints&lt;/li&gt;
&lt;li&gt;Learning React Native — the setup &lt;em&gt;is&lt;/em&gt; the point&lt;/li&gt;
&lt;li&gt;Extreme scale on day one&lt;/li&gt;
&lt;li&gt;Template stack is wrong for you (e.g., you need Firebase, template is Supabase)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A two-minute decision framework
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Screen architecture obvious in 5 min of whiteboard? → buy&lt;/li&gt;
&lt;li&gt;App describable as "X for Y"? → buy&lt;/li&gt;
&lt;li&gt;Timeline &amp;lt; 60 days? → buy&lt;/li&gt;
&lt;li&gt;Billing a client &amp;gt; $5,000? → buy&lt;/li&gt;
&lt;li&gt;Learning React Native? → build the first, buy the second&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Two or more "buy" answers and you don't need a calculator.&lt;/p&gt;

&lt;h2&gt;
  
  
  Disclosure
&lt;/h2&gt;

&lt;p&gt;I work on production-grade React Native templates ($49–99 on RN 0.81 / Expo SDK 54 / Supabase). Bias acknowledged. The math still leans toward buying for most indie apps — and when it doesn't, the post above tells you exactly why.&lt;/p&gt;

&lt;p&gt;Whatever template you evaluate, run the buyer's checklist above. A real template ships a real backend (schema, RLS, server routes), passing App Store review, with EAS Build profiles ready to go. If it doesn't ship those, the price you spent on it bought you nothing.&lt;/p&gt;

&lt;p&gt;If none of the templates on the market match your app shape, build from scratch. That's the only honest answer to the buy-vs-build question.&lt;/p&gt;




&lt;p&gt;For the longer breakdown — the FAQ and the line-by-line "what a real template ships" inventory — see &lt;a href="https://www.applighter.com/blog?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=buy-vs-build-react-native-2026" rel="noopener noreferrer"&gt;the Applighter blog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What's the foundation work that ate the most hours on your last React Native project? Drop it in the comments — I'm collecting the unglamorous setup tasks indie devs underestimate for a follow-up.&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>expo</category>
      <category>supabase</category>
      <category>mobile</category>
    </item>
  </channel>
</rss>
