News

什么是 Supabase?

用新手也能听懂的方式,快速搞懂 Supabase(一个开源的 Firebase 替代方案)

什么是 Supabase?

如果你是前端/独立开发新手,想做一个带登录、存数据、还能实时刷新消息的小应用,但又不想自己买服务器、装数据库、写一堆后端代码——Supabase 就像一套“现成的后端”,开箱即用。

用大白话解释:Supabase 是什么?

一句话:Supabase 把一些后端能力打包成服务,让你可以快速开发应用,不需要自己再拼凑这些能力。

它把做应用常用的后端能力打包好放到云端,常见功能包括:

  • 数据库(PostgreSQL):像“云端表格”,用来存你的用户、文章、订单等数据。
  • 认证(Auth):登录/注册/第三方登录(微信/Apple/Google 等)。
  • 实时(Realtime):数据一改,页面自动收到更新(像聊天室那样)。
  • 存储(Storage):上传图片、视频、文件并生成可访问链接。
  • 自动 API:建好表就有现成的 REST / GraphQL 接口可用。

它跟 Firebase 很像,但 Supabase 基于“关系型数据库 PostgreSQL”,支持 SQL,数据结构更清晰、可迁移、也能自托管(因为开源)。

如果没有 Supabase,我们会怎么开发?

大致要自己拼这几块:

  • 服务器与数据库:买云服务器、装 PostgreSQL,配置备份/监控/高可用;或用托管数据库(RDS/Neon 等)。
  • 后端 API:选框架(Express/NestJS/FastAPI 等),设计接口、处理鉴权、做数据校验、分页、错误处理。
  • 认证登录:实现注册/登录/重置密码、第三方登录(OAuth)、邮件/短信发送、Token/Session 管理与安全加固。
  • 文件存储:接入 S3/Cloudflare R2,做上传、预签名 URL、访问控制、CDN、图片裁剪与清理策略。
  • 实时能力:自建 WebSocket/Socket.IO,或基于数据库变更流/Redis PubSub,考虑横向扩展和断线重连。
  • 权限与安全:建 RBAC/ABAC,或使用 SQL/RLS 在数据层做细粒度授权,防注入与速率限制。
  • 运维与观察性:部署 CI/CD、环境隔离、日志/指标/告警、密钥管理、成本监控。

Supabase 的价值在于把这些常见“基础设施”打包好,很多项目可以直接可用或稍作配置就能跑起来。

Supabase 的缺点与取舍(成本与依赖)

  • 成本会随使用叠加:数据库算力、存储、带宽、实时连接数、认证发送等都会计费。功能用得越多、数据越大,账单越高。
  • 依赖度高带来迁移成本:如果你的认证、存储、实时、边缘函数都绑定在 Supabase,上线后要迁走会比较麻烦。虽然它开源可自托管,但迁移/运维都是额外工作量。
  • 策略与安全有学习曲线:RLS 很强大,但不熟悉 SQL/策略的人容易配错,要花时间建立正确的权限模型与测试。
  • 产品边界与配额限制:某些高级功能或极端场景(超长连接、大规模并发、特殊扩展)可能触到配额/限制,需要额外架构或升级方案。
  • 区域与网络:项目所在地域若离用户较远,可能有额外延迟;需要结合 CDN/边缘节点优化。

如何降低风险(简要建议):

  • 把数据访问封装在项目自己的仓库/服务层,避免在全局散落 Supabase 调用,减少未来替换成本。
  • 尽量以标准能力为核心(PostgreSQL + Auth),对“可替代”的周边能力(如对象存储)保留切换空间。
  • 建立成本监控与告警,按月检查用量;对大文件走独立 CDN/对象存储策略以降本。

为什么新手适合用 Supabase?

  • 开箱即用:注册 → 新建项目 → 直接写前端代码,后端少写很多。
  • 有“真”数据库:PostgreSQL 很强大,后期要做复杂查询也不怕。
  • 学习门槛低:有清晰的可视化控制台、文档多、示例多。
  • 开源可迁移:将来想自己部署或换云厂商更容易。

什么时候该用它?

  • 原型/黑客松/MVP:想一两天做出一个能用的版本。
  • 个人项目/独立产品:一个人搞定全栈,迭代快。
  • 内部工具/小团队应用:快速上线,后续还能扩展。

不太适合的场景:需要非常定制化的底层网络/消息队列,或对极限性能有苛刻要求的超大型系统(但大多数项目都用不上这些)。

5 分钟上手指引(Next.js 版)

  1. 在 Supabase 控制台创建一个 Project;建表 todos,包含列:id(int,自增,主键)、title(text)、done(boolean,默认 false)。
  2. 本地创建 Next.js 项目并安装 SDK:
npx create-next-app@latest supa-todos --ts
cd supa-todos
npm i @supabase/supabase-js
  1. 填写 .env.local(Project Settings → API 能看到 URL 和 anon key):
NEXT_PUBLIC_SUPABASE_URL=https://YOUR-PROJECT.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=YOUR-ANON-KEY
  1. 新建 lib/supabaseClient.ts
// lib/supabaseClient.ts
import { createClient } from '@supabase/supabase-js'
 
export const supabase = createClient(
  process.env.NEXT_PUBLIC_SUPABASE_URL!,
  process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
  1. app/page.tsx 放入最小示例(新增/列表/实时):
// app/page.tsx
'use client'
import { useEffect, useState } from 'react'
import { supabase } from '../lib/supabaseClient'
 
type Todo = { id: number; title: string; done: boolean }
 
export default function Page() {
  const [todos, setTodos] = useState<Todo[]>([])
  const [title, setTitle] = useState('')
 
  async function load() {
    const { data, error } = await supabase
      .from('todos')
      .select('*')
      .order('id', { ascending: false })
    if (!error && data) setTodos(data as Todo[])
  }
 
  async function addTodo(e: React.FormEvent) {
    e.preventDefault()
    if (!title.trim()) return
    const { error } = await supabase.from('todos').insert([{ title, done: false }])
    if (!error) setTitle('')
  }
 
  async function toggleTodo(id: number, done: boolean) {
    await supabase.from('todos').update({ done: !done }).eq('id', id)
  }
 
  useEffect(() => {
    load()
    const channel = supabase
      .channel('todos-changes')
      .on('postgres_changes', { event: '*', schema: 'public', table: 'todos' }, load)
      .subscribe()
    return () => {
      supabase.removeChannel(channel)
    }
  }, [])
 
  return (
    <main style={{ maxWidth: 480, margin: '40px auto' }}>
      <h1>Todos</h1>
      <form onSubmit={addTodo} style={{ display: 'flex', gap: 8 }}>
        <input
          value={title}
          onChange={(e) => setTitle(e.target.value)}
          placeholder="Add todo"
        />
        <button type="submit">Add</button>
      </form>
      <ul>
        {todos.map((t) => (
          <li key={t.id}>
            <label>
              <input
                type="checkbox"
                checked={t.done}
                onChange={() => toggleTodo(t.id, t.done)}
              />
              <span style={{ marginLeft: 8, textDecoration: t.done ? 'line-through' : 'none' }}>
                {t.title}
              </span>
            </label>
          </li>
        ))}
      </ul>
    </main>
  )
}

安全提示:为方便演示,建议先在开发环境放宽 RLS(行级安全)策略,或创建一个仅供演示的策略允许运行匿名读写;上线前务必收紧权限与规则。

和 Firebase 的区别(新手关心版)

两者都是“省心后端”。主要差别:

  • Firebase 用 NoSQL(文档型数据库),上手快;Supabase 用 PostgreSQL(关系型),更适合结构清晰、有关系的业务数据。
  • Supabase 开源,可自托管;Firebase 闭源,更依赖官方生态。
  • 两者都有认证、存储、实时能力;选择哪个更多看团队习惯和数据模型需求。

价格怎么控制?

  • 有免费层,做个人/学习/原型足够起步。
  • 用量上来再升级,费用主要跟数据库算力、存储、带宽相关。

获取帮助

Supabase 拥有活跃且乐于助人的社区:

总结

  • 把 Supabase 当成“现成的后端”:登录、数据库、存储、实时统统有。
  • 先用免费层做起来,遇到问题再逐步学习、加功能。
  • 基于 PostgreSQL,后期可扩展、可迁移、可自托管,长远更省心。

如果你刚入门想做第一个能上线的小产品,Supabase 是非常稳妥的选择。