数字/事实:Supabase 官方维护了 JavaScript/TypeScript、Flutter、Swift、Kotlin、Python 等语言的客户端库,覆盖 Web、iOS、Android 和后端脚本。这一节我们讲这些 SDK 的共性设计、各自适用场景,以及怎么选,避免"为了用而用"错配平台。
不管哪种语言,官方 SDK 都封装了同样的四件事:认证、数据库查询、实时订阅、存储。所以你学会 JS 版,切到 Flutter 只是换语法,心智模型不变。下面用 JS 和 Flutter 对比同一段"登录后查待办":
// JavaScript / TypeScript import { createClient } from '@supabase/supabase-js' const supabase = createClient(URL, ANON) await supabase.auth.signInWithPassword({ email, password }) const { data } = await supabase.from('todos').select()
// Flutter (Dart) import 'package:supabase_flutter/supabase_flutter.dart'; final supabase = Supabase.instance.client; await supabase.auth.signInWithPassword(email: email, password: password); final data = await supabase.from('todos').select();
可以看到 auth、from().select() 的调用形态高度一致。这降低了多端团队的协作成本——后端写策略、前端各端照同一套接口调。
下面 SVG 把 SDK 与目标平台、典型用途画成矩阵:

SDK 既能用 anon key(走 RLS)也能用 service_role(绕过 RLS)。前者用于前端和受信任客户端,后者只用于服务端。以 Python 为例:
# 后端脚本用 service_role 做管理员批量任务 from supabase import create_client supabase = create_client(URL, SERVICE_ROLE) # 仅在服务端 res = supabase.table('todos').select('*').execute() print(res.data)
注意:Python 脚本若在本地跑、不在前端,用 service_role 没问题;但同样的逻辑绝不能原样搬进浏览器包。
背景:一个团队要做 Web、iOS、Android 三端笔记应用,后端只想维护一套。
操作过程:
signInWithPassword,拿到 JWT 后查询走同一套 RLS。postgres_changes 监听 notes 表。结果:后端零定制代码,三端共用认证、权限、实时。新端(如 CLI)加入只需接 SDK,不碰后端。
解读:这正是 SDK 矩阵的价值——后端收敛成"数据库 + 策略",多端差异被 SDK 吸收。若当初每端写一套 REST 接口,维护成本翻三倍。
变式:若某端需要离线优先(如移动端弱网),可用 SDK 的本地持久化能力先写本地、再同步;Supabase 的实时和幂等写入能支撑这类最终一致场景。
提醒:不要把某个端的 service_role 密钥复制到其他端或前端。service_role 是全局管理员,跨端共享等于把数据库钥匙分给所有客户端。
建议:我们建议多端团队约定"后端只管数据+策略,端只管用 SDK",把接口差异消灭在 SDK 层。这样加新端几乎是零后端成本。
前面讲了三端共用后端,实时同步是其中最见功力的部分。下面把"监听 notes 表变更"在三种 SDK 里写出来,你能看到形态一致、只有语法差异:
// JavaScript / TypeScript const channel = supabase .channel('notes') .on('postgres_changes', { event: '*', schema: 'public', table: 'notes' }, (payload) => console.log('变更:', payload)) channel.subscribe()
// Flutter (Dart) final channel = supabase .channel('notes') .onPostgresChanges( event: PostgresChangeEvent.all, schema: 'public', table: 'notes', callback: (payload) => print('变更: $payload'), ) channel.subscribe()
# Python(服务端/脚本里也能订阅) await supabase.channel('notes').on( 'postgres_changes', {'event': '*', 'schema': 'public', 'table': 'notes'}, lambda payload: print('变更:', payload), ).subscribe()
💡 关键直觉:实时能力的"订阅—回调"模型在每种 SDK 里都一样,区别仅在命名风格(驼峰 vs 下划线)。这意味着你在一端调通的实时逻辑,换端基本是翻译而非重写。后端完全不用为实时写任何代码,通道由 Realtime 服务自动维护。
背景:某团队把 supabase-js 从 v1 升到 v2,登录后 session 拿不到,全线登录态丢失。
操作过程:
auth.session() 改为异步的 auth.getSession(),且默认不再自动持久化到 localStorage(需显式引入 @supabase/ssr 或自管存储)。// v2 正确取法 const { data: { session } } = await supabase.auth.getSession() console.log('当前会话:', session?.user?.email)
@supabase/ssr 的 createBrowserClient,把 session 存回 cookie。结果:升级后功能回归,同时借机把存储层规范化。
解读:大版本升级最易踩的是"同步改异步"和"默认行为收紧"。升级前先扫一遍 release notes 里标 BREAKING 的条目,比上线后救火省心。我们主张 SDK 升级也像迁移一样,先在预发环境验一遍再推生产。
⚠️ 常见坑:有人图省事不升级、长期停在 v1,结果新出的安全修复和 RLS 特性都用不上,越拖越难升。SDK 和我们写的业务代码一样需要定期维护——把它纳入依赖更新节奏,别等到被迫大跨版本。
下一节看社区资源:模板、教程、论坛在哪,怎么用它们把开发再提速。