Source: https://www.hype-stack.dev/stacks/nextjs-supabase-boilerplate

# Next.js Supabase Boilerplate Alternative: Postgres Anywhere

> Supabase is not hard to leave because of the hosting. It is hard to leave because of where you decided to put your
> authorization.

Next.js on Vercel with Supabase behind it is a common stack for small teams. You get Postgres, auth, storage, and
realtime as managed services, and the free tiers can be enough for an early prototype.

Teams often look for a nextjs supabase boilerplate alternative when they need more control over where application logic
and authorization live. At that point, the app may depend on conventions from both platforms, and changing those
conventions can require more than a configuration update.

**To be clear about what this is**

Hype Stack does not include Supabase or replace it. It is a codebase you run: a Hono backend, a Prisma and Kysely
  schema, and a Postgres connection string that can point at Supabase, RDS, Neon, or a container on a VPS. If you want
  to keep Supabase as your database and drop the rest of the platform, that works and is a normal thing to do.

## What the Supabase stack does well

Supabase can shorten the path to a working feature. Row-level security, an instant API over your tables, hosted auth
with social providers, and storage with signed URLs remove several setup tasks. For hackathons, internal tools, and
products that are comfortable with managed infrastructure, it can be a strong default with little reason to switch.

The database underneath is standard Postgres. Your data is not in a proprietary store, your schema is standard, and
`pg_dump` works. That makes leaving Supabase possible even when the surrounding application changes take real work.

## Where the two part ways

|  | Hype Stack | Next.js + Supabase |
| --- | --- | --- |
| Where rules live | Permission checks in backend middleware, as strings like manage:billing you can read and test | RLS policies in SQL, enforced by the database and debugged in the dashboard |
| Auth data | Your own user, session, and account tables, or WorkOS if you would rather not run it | Supabase Auth, in the platform's schema, tied to the project |
| Client to server | Hono route types inferred into a typed SDK, so an endpoint is typed on the client immediately | Generated database types, then hand-written fetch or RPC calls around them |
| Where it runs | Best on Vercel and Supabase cloud; self-hosting exists but is not the happy path | A Node process and a Postgres, anywhere Docker runs |
| Setup cost | A project URL and an anon key, and you are querying | Compose packs, run migrations, bring your own services |

[Browse all packs](/packs)

## Row-level security changes the authorization model

Several rows in that table come down to preference. Authorization changes how you write features, so it is worth making
that choice explicitly.

Supabase encourages you to push authorization into the database, so the client can talk to Postgres directly and RLS
decides what it sees. When the policies are correct, this model keeps enforcement close to the data, and it has one
property application-level checks do not provide by themselves: it holds even for a query you forgot to guard, because
the database enforces it.

The reason it still splits opinion is what happens when a policy is wrong.

- **Errors are loud:** If authorization is wrong, something throws and I find out.
  **Rows quietly vanish:** A policy that is too strict can return fewer rows with no error. The page renders, the list is short, and the logs may not explain why. These bugs can be difficult to notice because the request still succeeds.
- **Debug it like code:** I can put a breakpoint on the check and step through it.
  **Debug it as SQL:** The rule is a policy expression evaluated by Postgres against a JWT claim. Reproducing it means impersonating a role in a SQL session, which is a genuine skill and a different one from reading a stack trace.
- **Reviewable in a pull request:** Permission changes show up in code review like everything else.
  **Depends entirely on your discipline:** Policies can be edited in a dashboard. If they are not in migrations, the rule that governs who sees what is not in git, so the repository does not record when or why it changed.

_RLS works well when policies live in migrations and someone on the team can review and debug them. Without those practices, policy errors can be difficult to trace._

Here authorization is application code. A request hits Hono middleware, the middleware resolves the user, their
organization, and their permission strings, and the route either runs or throws. It is more typing, it is a normal test
file, and it fails in a way you can read. It also gives up the guarantee above: forget the check on one route and there
is no database quietly covering for you.

Which model fits depends on the team's skills and the application's access patterns. Decide before migrating because the
choice affects how each protected feature is implemented.

## Which one fits you

**Is platform coupling a price you are happy to keep paying?**

- **Stay on Supabase:** Stay when managed infrastructure is a feature you want to pay for.
  - Row-level security, an instant API over your tables, hosted social login, and signed URLs remove setup work
  - A project URL and an anon key, and you are querying
  - Platform coupling is the trade-off, and some products will accept it for the managed services
- **Run the code yourself:** Move when you need more control over the application boundary.
  - A backend that runs the same way on your laptop and in production
  - User, session, and account tables inside your own migrations
  - Permission checks that show up in code review, because they are code

## Keep Supabase as managed Postgres

There is also a middle path: keep Supabase as the Postgres host and replace the other platform services as needed.

Point a connection string at it, run your own migrations, and move authorization into your backend a feature at a time.
You keep the managed database, the backups, and the dashboard you already know. What you give up is the client talking
to Postgres directly. This lets you migrate incrementally and stop if the extra control is not worth the work.

A Supabase migration does not have to move every service at once. Database hosting is separate from the work of changing
features that assume authorization happens inside Postgres.

## What our column is coupled to

A page arguing against coupling should be specific about its own. The stack this page recommends composes
`starter-saas-workos`, so sessions and the login screens go through WorkOS, a SaaS account with its own bill. Billing is
Stripe, same deal. Subscription state is cached in Valkey rather than Postgres, so that is a third service to run. The
starter is a slot rather than a fixture: pick the Better Auth variant instead and WorkOS goes away, at the cost of
running auth yourself.

The difference is where the coupling sits, not whether it exists. In this stack, it is behind an identity layer and a
webhook handler, both of which are files in your repository that you can read and replace. With Supabase, it can sit in
the shape of your queries and the location of your authorization rules, so removing it may require feature-level
changes. If you want zero third-party accounts, neither column fits; the free core is the relevant starting point.

The screens and the pack list follow. You can point the stack at a Supabase connection string if keeping the managed
database while moving application logic into Hono fits your requirements.



The framework side of this decision is in [Next.js Alternative](/stacks/nextjs-alternative), and the auth you get
instead of RLS in [Better Auth SaaS Template with Organizations Built In](/stacks/better-auth-saas-template). The wider
field of hosted backends, and the own-it option, is in [Supabase Alternatives](/stacks/supabase-alternatives).
