Supabase
lastmod 2026-09-10created 2022-04-1945 edits
The Open Source Firebase Alternative
Categories
Features
- Build backends easily
- Real-time DB engine built on Postgres using Elixir
- Changes reflected in real time over WebSockets
Architecture
- https://github.com/supabase/supabase/blob/master/i18n/README.ko.md
- PostgreSQL - PostgreSQL is an object-relational database system that has been developed and improved for over 30 years, and it is highly regarded for its reliability, feature robustness, and performance.
- Realtime is an Elixir server that lets you listen to PostgreSQL inserts, updates, and deletes using WebSockets. Supabase listens to Postgres's built-in replication functionality, converts the replication byte stream into JSON, and then broadcasts the JSON over WebSockets.
- PostgREST - is a web server that turns a PostgreSQL database directly into a RESTful API.
- Storage provides a RESTful interface for managing files stored in S3, using Postgres to manage permissions.
- postgres-meta is a RESTful API for managing Postgres that lets you fetch tables, add roles, and run queries.
- GoTrue is an SWT-based API for managing users and issuing SWT tokens.
- Kong is a cloud-native API gateway.
Environment variables
- POSTGRES_URL
- POSTGRES_PRISMA_URL
- POSTGRES_URL_NON_POOLING
- POSTGRES_USER
- POSTGRES_HOST
- POSTGRES_PASSWORD
- POSTGRES_DATABASE
- SUPABASE_SERVICE_ROLE_KEY
- SUPABASE_ANON_KEY
- SUPABASE_URL
- NEXT_PUBLIC_SUPABASE_ANON_KEY
- NEXT_PUBLIC_SUPABASE_URL
Why you shouldn't use varchar(n) by default
See the relevant item.
Limiting character count instead of varchar(n)
See PostgreSQL:Constraints#Character count limit. In short:
Quickstart guide Nextjs with supabase
You can check users in the SQL Editor:
Create a project:
npx create-next-app -e with-supabase my-app && cd my-app
## or
yarn create next-app -e with-supabase my-app && cd my-app
Rename the .env.local.example file to .env.local and check the following environment variables:
- NEXT_PUBLIC_SUPABASE_URL
- NEXT_PUBLIC_SUPABASE_ANON_KEY
-
SUPABASE_SERVICE_ROLE_KEY- What is this?
Run it and check.
Github authentication integration
See the Github OAuth page.
Google authentication integration
Configuration
To use the OAuth 2.0 flow, you will require the following information:
- Obtain OAuth credentials for your Google Cloud project in the Credentials page of the console. When creating a new credential, choose Web application. In Authorized redirect URIs enter
https://<project-id>.supabase.co/auth/v1/callback. This URL will be seen by your users, and you can customize it by configuring custom domains. - Configure the OAuth Consent Screen. This information is shown to the user when giving consent to your app. Within Authorized domains make sure you add your Supabase project's domain <project-id>
.supabase.co. Configure the non-sensitive scopes by making sure the following ones are selected:.../auth/userinfo.email,.../auth/userinfo.profile,openid. If you're selecting other sensitive scopes, your app may require additional verification. In those cases, it's best to use custom domains. - Finally, add the client ID and secret from step 1 in the Google provider on the Supabase Dashboard.
API Settings
The project settings page has the following items.
- Exposed schemas
- Default - public, storage, graphql_public
- List of schemas to expose in the API. Tables, views, and stored procedures in these schemas get API endpoints. public and storage are protected by default, i.e. they cannot be changed.
- Extra search path
- Default - public, extensions
- Extra schemas to add to the search path of every request. Multiple schemas must be comma-separated.
- Max rows
- Default - 1000
- Maximum number of rows returned from a view, table, or stored procedure. Limits payload size for accidental or malicious requests.
How to connect with a Postgres driver
When you press Supabase's Connect button, the URI shown will look like this:
But connecting with this, Method: Direct connection, probably requires IPv4 to be enabled (needs checking), and that is a paid service. So the connection will probably fail.
If you switch to Method: Transaction pooler, the connection address changes to something like this:
postgresql://postgres.[PROJECT-ID]:[YOUR-PASSWORD]@aws-1-ap-southeast-1.pooler.supabase.com:6543/postgres
The important part is that the username is postgres.[PROJECT-ID], and the host address and port number have also changed.
Note that you can change the password on the database settings page.
Self-Hosting with Docker
Learn how to configure and deploy Supabase with Docker.
Docker is the easiest way to get started with self-hosted Supabase. This guide assumes you are running the command from the machine you intend to host from.
Managing your secrets
Many components inside Supabase use secure secrets and passwords. These are listed in the self-hosting env file, but we strongly recommend using a secrets manager when deploying to production. Plain text files like dotenv lead to accidental costly leaks.
Some suggested systems include:
- Doppler
- Infisical
- Key Vault by Azure (Microsoft)
- Secrets Manager by AWS
- Secrets Manager by GCP
- Vault by Hashicorp
Architecture
Supabase is a combination of open source tools, each specifically chosen for Enterprise-readiness.
If the tools and communities already exist, with an MIT, Apache 2, or equivalent open license, we will use and support that tool. If the tool doesn't exist, we build and open source it ourselves.
- Kong is a cloud-native API gateway.
- GoTrue is an JWT based API for managing users and issuing JWT tokens.
- PostgREST is a web server that turns your PostgreSQL database directly into a RESTful API
- Realtime is an Elixir server that allows you to listen to PostgreSQL inserts, updates, and deletes using websockets. Realtime polls Postgres' built-in replication functionality for database changes, converts changes to JSON, then broadcasts the JSON over websockets to authorized clients.
- Storage provides a RESTful interface for managing Files stored in S3, using Postgres to manage permissions.
- postgres-meta is a RESTful API for managing your Postgres, allowing you to fetch tables, add roles, and run queries, etc.
- PostgreSQL is an object-relational database system with over 30 years of active development that has earned it a strong reputation for reliability, feature robustness, and performance.
Configuring services
Each system has a number of configuration options which can be found in the relevant product documentation.
Installing and running Supabase
# Get the code
git clone --depth 1 https://github.com/supabase/supabase
# Go to the docker folder
cd supabase/docker
# Copy the fake env vars
cp .env.example .env
# Pull the latest images
docker compose pull
# Start the services (in detached mode)
docker compose up -d
Then open http://localhost:8000/. The user ID/PW are:
- Username:
supabase - Password:
this_password_is_insecure_and_should_be_updated
To change them, edit the .env file.
Create API keys here. Check ANON_KEY or SERVICE_ROLE_KEY in the .env file.
What the Free Tier actually gets you
Supabase's free plan is surprisingly generous compared to other services. Here are the details.
- 500MB of database storage. This is PostgreSQL's base storage for tables, indexes, and data. For reference, 500MB can hold roughly 2 to 5 million rows of typical app data (users, posts, comments). Most MVP projects won't hit this for months.
- 1GB of file storage. For images, documents, and other files stored in Supabase Storage.
- 2GB of bandwidth. This is total egress bandwidth, combining all data transferred through the database and storage. This is where the free plan's bandwidth limit kicks in sooner than you'd expect.
- 50,000 monthly active users for Auth. Enough for most startups. For this to become a bottleneck, your business would have to be doing quite well.
- 500,000 Edge Function (Supabase's serverless functions) invocations per month. Enough for most use cases.
- Only up to two projects are allowed. One for production, one for staging. If you want to create multiple projects for experiments, this limit can matter quite a bit.
Anya ran a SaaS service on the free plan for 5 months. About 400 users, about 100MB of data, and moderate API traffic. She stayed well within the usage limits. The two-project limit was a letdown (she wanted to add a third project to experiment), but for her main product the free plan was enough.
Limits of the free tier
The bandwidth limit is the silent killer. 2GB seems like a lot, until you realize that data is transferred on every API call. A typical SaaS page load transfers about 50-100KB of data from Supabase. Do the math: with 500 daily active users, 20 API calls per user, and an average of 50KB per call, you use 500MB a day. At that rate, the 2GB allowance is used up in four days.
Anya ran into this in her fourth month after launch. Her app had a dashboard that loaded a fairly complex dataset on every visit, and users refreshed it several times a day. As users grew from 300 to 500, she went from "within limits" to "bandwidth limit exceeded" in about two weeks.
Another issue is database compute. The free tier also runs on shared compute. Anya saw API response times spike from 50ms to 300ms during peak hours. Not a serious problem, but visible in the metrics, and something that could become a problem as traffic grows.
Pro plan: a sensible default
When Anya upgraded, she moved to the $25/month Pro plan. Here is what changed.
- 8GB of database storage. 16x the free tier.
- 100GB of bandwidth. This was the biggest change. Going from 2GB to 100GB meant she no longer had to worry about bandwidth.
- Dedicated compute (micro instance). Consistent performance instead of shared resources.
- 100,000 monthly active users for Auth.
- 2 million Edge Function invocations.
- No limit on the number of projects. Create as many as you need.
- Backups retained for 7 days. The free tier has no automatic backups, which is pretty terrifying when you think about it.
The $25/month Pro plan is really cheap for what you get. Anya compared it to running her own Postgres instance on AWS (RDS t4g.micro, about $13/month, plus load balancing, an auth service, storage, and bandwidth) and estimated that AWS would cost around $80-120/month, not counting the time spent managing it.
The bandwidth and compute included in the Pro plan are sized for apps with up to a few thousand active users. Beyond that, you should consider compute add-ons.
Compute add-ons: where costs actually grow
Supabase's pricing model is unusual in that the base plan price is relatively fixed, and the variable cost comes from compute add-ons. If your database needs more processing power, you attach a bigger compute instance.
- Micro (Pro's default): 2-core ARM, 1GB RAM — included in Pro
- Small: 2-core ARM, 2GB RAM — $50/month extra
- Medium: 2-core ARM, 4GB RAM — $100/month extra
- Large: 2-core ARM, 8GB RAM — $200/month extra
- XL and up: scales further for heavier workloads
In Anya's case, the micro instance worked fine until her app reached about 2,000 daily active users running complex dashboard queries. Upgrading to a Small instance ($50 extra) then solved the performance problems. Her monthly Supabase bill came to $75 in total, still far cheaper than building self-managed infrastructure.
The key point is that compute cost is the main factor in scaling. Storage can grow and bandwidth can spike, but for most applications, what actually needs upgrading is the compute instance, because running complex queries over growing datasets requires more CPU and memory.
Team plan: a stepping stone to enterprise
The $599/month Team plan targets companies that need SOC 2 compliance, priority support, and SSO (single sign-on). The functional difference from the Pro plan is relatively small: more storage, higher bandwidth, and a longer backup retention period. In effect, you are paying for compliance and support.
Anya isn't at that stage yet. She knows she will get there when her first enterprise customer asks for a SOC 2 report. For now, though, Pro plus a compute add-on handles her workload.
Strategies for staying cheap
Here is what Anya learned about keeping Subabase costs low as an app scales.
- Use RLS instead of middleware. Row-level security policies run inside the database, which means filtered queries return less data. Less data returned means less bandwidth consumed. If you fetch the whole dataset and then filter in application code, you are literally paying for avoidable bandwidth.
- Paginate aggressively. Why load 500 rows when the user only sees 20? Supabase supports the range header and limit/ / offset parameters. Use them. Anya cut bandwidth usage by 60% by implementing proper pagination in her dashboard tables.
- Cache on the client. React Query, SWR, or plain localStorage caching dramatically reduces round trips to Supabase. Putting a 5-minute cache TTL on data that only changes hourly eliminates thousands of pointless API calls a day.
- Use database functions for heavy lifting. Instead of pulling data into the app, transforming it, and pushing it back, write a Postgres function that does all the work inside the database. One function call replaces three round trips.
- Monitor bandwidth. The Supabase dashboard shows usage in real time. Set up alerts before you approach the limit, not after you pass it. Anya checks hers weekly, the same way she checks her bank account.
Let agents handle the ops tax
One cost that doesn't show up on the Supabase bill is developer time spent on data operations. Bulk updates, cleanup passes, syncing records between systems: these eat time that could go toward building features.
The Supabase Inventory Tracker agent picks up the ops work Anya used to do by hand. She runs an e-commerce product, and keeping inventory levels accurate between her Supabase database and her Shopify store used to eat part of every week. The agent monitors inventory levels, flags discrepancies, and records updates without her writing one-off scripts.
For Anya, the math is simple. She pays $ 75/month for Supabase infrastructure. Using the agent for data operations saves her 5-10 hours of developer time a month. At her consulting rate, those hours are worth far more than the infrastructure cost. The most expensive part of running a database was never the database itself. It was the human time spent looking after the data.
Try These Agents
- Supabase Inventory Tracker — Track inventory levels, flag discrepancies, and keep stock data accurate in Supabase
- Supabase Data Sync Agent — Sync data between Supabase tables and external sources without manual scripts
- Supabase Database Cleanup Agent — Find and resolve duplicate, orphaned, and stale records automatically
Troubleshooting
Multiple accounts with the same email address in the same linking domain detected: default
- error=server_error
- error_code=500
- error_description=Multiple accounts with the same email address in the same linking domain detected: default
The single account registered with the OAuth service you are using (github in my case) may have multiple emails registered.
In short, don't register secondary emails in supabase.auth.
Redirected to http://localhost:3000 after OAuth login
Update the Site URL in the Authentication > URL Configuration menu.
See also
- firebase
- supabase
- strapi
- hasura
- Amplify
- bknd - Lightweight Firebase/Supabase alternative
- Nao - Cursor for data
Favorite site
Tutorials
- AWS Amplify
- Bknd
- CreateServerComponentClient
- Firebase
- GBrain
- GitHub
- JavaScript:Libraries
- Nao
- Next.js
- Open Source
- Oxy
- PgBouncer
- PostgreSQL
- PostgreSQL:RowSecurityPolicies
- PostgreSQL:View
- React
- Strapi
- Supabase MCP Server
- Supabase-py
- Supabase:Auth
- Supabase:CLI
- Supabase:Database
- Supabase:Database:NextAuth
- Supabase:Edge
- Supabase:JWTSigningKeys
- Supabase:Paddle
- Supabase:Queues
- Supabase:Vault
- SuperAgent
- TypeScript
- Uppy