<?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: Calebe Aires</title>
    <description>The latest articles on DEV Community by Calebe Aires (@calebeaires).</description>
    <link>https://dev.to/calebeaires</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F111975%2F572ac57c-ca62-40d6-9378-c7f02ac88796.png</url>
      <title>DEV Community: Calebe Aires</title>
      <link>https://dev.to/calebeaires</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/calebeaires"/>
    <language>en</language>
    <item>
      <title>A Go + React monorepo starter with auth and multi-tenancy</title>
      <dc:creator>Calebe Aires</dc:creator>
      <pubDate>Thu, 09 Apr 2026 17:15:51 +0000</pubDate>
      <link>https://dev.to/calebeaires/a-go-react-monorepo-starter-with-auth-and-multi-tenancy-57f7</link>
      <guid>https://dev.to/calebeaires/a-go-react-monorepo-starter-with-auth-and-multi-tenancy-57f7</guid>
      <description>&lt;p&gt;Every time I start a new project, I do the same thing.&lt;/p&gt;

&lt;p&gt;Set up the Go backend. Set up the React frontend. Figure out how they talk to each other in dev. Figure out how they deploy together. Add auth. Add sign up, sign in, sign out. Protect the routes. Store the token somewhere. And then , finally , I can start working on the thing I actually wanted to build.&lt;/p&gt;

&lt;p&gt;That part is always the same. And it's always slow.&lt;/p&gt;

&lt;p&gt;So I searched on GitHub for a starter that could save me this work. I found a lot of repos, but most of them had one of these problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only the backend, no frontend&lt;/li&gt;
&lt;li&gt;Only the frontend, no backend&lt;/li&gt;
&lt;li&gt;Auth was "just add your own provider later"&lt;/li&gt;
&lt;li&gt;Built for a tutorial, not for production&lt;/li&gt;
&lt;li&gt;Old versions of everything&lt;/li&gt;
&lt;li&gt;No multi-tenancy, and adding it later is painful&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I just wanted one repo where I could clone it, set two env vars, run &lt;code&gt;make dev&lt;/code&gt;, and start writing my feature. That repo didn't exist the way I wanted it. So I built it.&lt;/p&gt;

&lt;h2&gt;
  
  
  gin-react-monorepo
&lt;/h2&gt;

&lt;p&gt;Here it is: &lt;a href="https://github.com/calebeaires/gin-react-monorepo" rel="noopener noreferrer"&gt;github.com/calebeaires/gin-react-monorepo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's a full-stack monorepo with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Go + Gin&lt;/strong&gt; on the backend&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;React 19 + Vite + TypeScript&lt;/strong&gt; on the frontend&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tailwind v4 + shadcn/ui&lt;/strong&gt; for the UI&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authula&lt;/strong&gt; for email/password auth (lives in your codebase, no SaaS)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Neon Postgres&lt;/strong&gt; with schema-per-tenant multi-tenancy&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bun&lt;/strong&gt; as the ORM&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Single binary deploy&lt;/strong&gt; , Go embeds the built React app&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You clone it, set &lt;code&gt;DATABASE_URL&lt;/code&gt; and &lt;code&gt;AUTHULA_SECRET&lt;/code&gt;, run &lt;code&gt;make dev&lt;/code&gt;, and you already have sign up, sign in, protected routes, organizations, members, roles, and tenant-scoped endpoints working.&lt;/p&gt;

&lt;h2&gt;
  
  
  The parts I didn't want to write again
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Auth that just works
&lt;/h3&gt;

&lt;p&gt;You sign up, you get a token, the token goes in a Bearer header, the middleware checks it on every request. No magic. No third-party dashboard. The auth code is in the repo and you can change it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multi-tenancy out of the box
&lt;/h3&gt;

&lt;p&gt;This is the part I hate doing from scratch. Every B2B app needs organizations. Users belong to orgs. Each org has its own data. Roles. Invites. All of it.&lt;/p&gt;

&lt;p&gt;The repo uses &lt;strong&gt;schema-per-tenant&lt;/strong&gt; on Postgres. Each org gets its own schema (&lt;code&gt;tenant_&amp;lt;slug&amp;gt;&lt;/code&gt;). When a request comes in with the &lt;code&gt;X-Org-Slug&lt;/code&gt; header, the middleware starts a transaction and sets &lt;code&gt;search_path&lt;/code&gt; to that tenant's schema. Your handler doesn't know or care , it just queries as normal and the data is isolated.&lt;/p&gt;

&lt;p&gt;Creating an org creates the schema. Deleting an org drops it. Owners, admins and members have different permissions. It's all already there.&lt;/p&gt;

&lt;h3&gt;
  
  
  Frontend and backend that actually talk in dev
&lt;/h3&gt;

&lt;p&gt;In development, Vite runs on &lt;code&gt;:5173&lt;/code&gt; and Go runs on &lt;code&gt;:8081&lt;/code&gt;. Vite proxies &lt;code&gt;/api&lt;/code&gt; and &lt;code&gt;/auth&lt;/code&gt; to the Go server, so everything is same-origin and you don't fight CORS.&lt;/p&gt;

&lt;p&gt;In production, Vite builds the React app to static files, Go embeds them with &lt;code&gt;//go:embed&lt;/code&gt;, and you ship &lt;strong&gt;one binary&lt;/strong&gt;. One file, one process, one port. No Nginx. No separate static server. No Docker Compose with three services.&lt;/p&gt;

&lt;h3&gt;
  
  
  A clear place to add your feature
&lt;/h3&gt;

&lt;p&gt;The README has a full tutorial for adding a "Projects" feature end to end , model, migration, handler, route, frontend page. Six steps, tenant-isolated, authenticated, done.&lt;/p&gt;

&lt;p&gt;That's the whole point. The boring stuff is done. You just add the thing you care about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who this is for
&lt;/h2&gt;

&lt;p&gt;If you're like me and you want to build a B2B SaaS or any app with accounts and organizations, and you don't want to spend the first week of every project wiring up the same boilerplate, this is for you.&lt;/p&gt;

&lt;p&gt;If you like Go but don't want to pick a frontend stack from scratch every time, this is for you.&lt;/p&gt;

&lt;p&gt;If you want multi-tenancy done the right way without reading ten blog posts about search_path, this is for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  I need your help
&lt;/h2&gt;

&lt;p&gt;This is open source (MIT) and I want it to grow. I built the first version for myself, but a starter like this only gets really good when more people use it and push back on the decisions.&lt;/p&gt;

&lt;p&gt;So if this sounds useful to you, here's how you can help:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Try it out.&lt;/strong&gt; Clone it, run &lt;code&gt;make dev&lt;/code&gt;, build something small with it. Tell me what broke, what felt weird, what was missing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Star the repo.&lt;/strong&gt; It's a small thing but it helps other people find it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open issues.&lt;/strong&gt; Bugs, ideas, questions, "why did you do it this way" , all welcome.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Send PRs.&lt;/strong&gt; Some things I'd love help with: OAuth providers (Google, GitHub) as Authula plugins, a better invite flow, tests, Docker + Fly.io deploy examples, i18n for more languages, dark mode polish.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Share it.&lt;/strong&gt; If you know someone stuck doing the same boilerplate over and over, send it their way.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I want this to be the repo I wish I had found on GitHub. I can't get it there alone.&lt;/p&gt;

&lt;p&gt;Link: &lt;a href="https://github.com/calebeaires/gin-react-monorepo" rel="noopener noreferrer"&gt;github.com/calebeaires/gin-react-monorepo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks for reading. Now go build the thing you actually wanted to build.&lt;/p&gt;

</description>
      <category>go</category>
      <category>react</category>
      <category>webdev</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
