惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

The Cloudflare Blog
L
LangChain Blog
WordPress大学
WordPress大学
V
V2EX
M
MIT News - Artificial intelligence
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Stack Overflow Blog
Stack Overflow Blog
J
Java Code Geeks
F
Fortinet All Blogs
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
腾讯CDC
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
D
Docker
Recent Announcements
Recent Announcements
GbyAI
GbyAI
博客园 - 叶小钗
小众软件
小众软件
Hugging Face - Blog
Hugging Face - Blog
T
The Blog of Author Tim Ferriss
人人都是产品经理
人人都是产品经理
Engineering at Meta
Engineering at Meta
Y
Y Combinator Blog
雷峰网
雷峰网
The GitHub Blog
The GitHub Blog

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
Supabase basics with Node.js
Željko Šević · 2026-06-06 · via DEV Community

Željko Šević

Supabase is an open-source backend platform built around managed PostgreSQL. You get a database, auto-generated REST APIs (via PostgREST), Auth, file Storage, Realtime subscriptions, and Edge Functions - with a dashboard and SQL editor on top.

Compared to running Postgres yourself, Supabase adds hosted infra, API layers, and product features without you wiring them up. Compared to an ORM-only stack, you often talk to Postgres through the Supabase client or SQL, with RLS (row level security) enforcing access at the database layer.

Prerequisites

  • Supabase account (free tier is enough for learning)
  • Node.js version 26
  • @supabase/supabase-js installed (npm i @supabase/supabase-js)

Create a project and database

  1. In the Supabase dashboard, choose New project, pick a region, and set the database password.
  2. Wait until the project is ready.
  3. Open SQL Editor and run the schema below.

The Table Editor is fine for quick experiments; SQL Editor keeps schema reproducible in git and reviews.

create table if not exists public.todos (
  id bigint generated always as identity primary key,
  title text not null,
  done boolean not null default false,
  created_at timestamptz not null default now()
);

create or replace function public.list_open_todos()
returns setof public.todos
language sql
security definer
set search_path = public
as $$
  select * from public.todos where done = false order by id;
$$;

create or replace function public.mark_todo_done(todo_id bigint)
returns setof public.todos
language sql
security definer
set search_path = public
as $$
  update public.todos set done = true where id = todo_id returning *;
$$;

grant execute on function public.list_open_todos() to service_role;
grant execute on function public.mark_todo_done(bigint) to service_role;

This schema skips RLS setup because this post uses the secret key from Node.js, which bypasses RLS. For browser or mobile clients, use the publishable key instead - it obeys Row Level Security when you enable it on tables.

list_open_todos is a Postgres function exposed as an RPC endpoint.

Postgres functions default to security invoker: they run with the caller's permissions, so RLS applies as that role. security definer runs the function as its owner (often a privileged database role), not as the caller.

API keys and connection

On the project Overview tab you will find:

  • Project URL (https://<ref>.supabase.co) — for SUPABASE_URL
  • Publishable key (sb_publishable_..., legacy anon) — for browsers and mobile apps where RLS should limit access; this post does not use it

For Node.js backends, use a secret key from Project SettingsAPI Keys:

  • Secret key(s) (sb_secret_...) - full data access, bypasses RLS; trusted servers only, never in client bundles or public repos. Replaces the legacy service_role key.
  • Reveal or create a secret key in the dashboard (legacy projects: Legacy anon, service_role API keys tab → service_role).

The Supabase JS client talks to PostgREST and can query tables (from) and call registered functions (rpc) only after they exist. It does not run DDL (create table, create function, grant, and similar), so apply the schema in the SQL Editor (or via Supabase CLI migrations in larger projects).

Store values in environment variables:

SUPABASE_URL=https://<ref>.supabase.co
SUPABASE_SECRET_KEY=your-secret-key

Client setup

Create a client with the project URL and secret key. Read values from the environment in real apps; never commit the secret key.

import { createClient } from '@supabase/supabase-js';

const supabase = createClient(
  process.env.SUPABASE_URL,
  process.env.SUPABASE_SECRET_KEY
);

Every table you create in the public schema is available as supabase.from('<table>'). Custom SQL functions are called with supabase.rpc('<function_name>').

Insert data

Insert one or more rows and return the created records with .select().

const { data, error } = await supabase
  .from('todos')
  .insert([
    { title: 'Learn Supabase client', done: false },
    { title: 'Run RPC example', done: false },
    { title: 'Ship demo', done: true },
  ])
  .select();

if (error) {
  throw new Error(error.message);
}

console.log(data);

Read, update, and delete

Select with filters and ordering:

const { data, error } = await supabase
  .from('todos')
  .select('*')
  .eq('done', false)
  .order('id');

Update matching rows:

const { data, error } = await supabase
  .from('todos')
  .update({ done: true })
  .eq('id', 1)
  .select();

Delete matching rows:

const { error } = await supabase
  .from('todos')
  .delete()
  .eq('id', 1);

Chain .eq(), .in(), .limit(), and other filter helpers the same way across operations.

RPC

Call a database function by name. Our list_open_todos() returns open todos without repeating filter logic in the app.

const { data, error } = await supabase.rpc('list_open_todos');

if (error) {
  throw new Error(error.message);
}

console.log(data);

Functions with parameters map to a second argument:

await supabase.rpc('mark_todo_done', { todo_id: 42 });

Define parameters in SQL (todo_id bigint) and grant execute to service_role when calling RPC from a secret-key backend.

What else matters

  • Row Level Security (RLS) - When enabled on a table, Postgres denies access until policies allow it. The publishable key is subject to RLS; the secret key is not. Add policies per role (anon, authenticated) and operation when you turn RLS on.
  • Auth - Supabase Auth stores users in auth.users. After sign-in, the client JWT includes the authenticated role so policies can use auth.uid() for per-user rows.
  • Migrations - Avoid changing production only via the dashboard. Track SQL in versioned migration files and apply with the Supabase CLI (supabase db push, linked projects) so environments stay aligned.
  • Generated types - Run supabase gen types typescript --project-id <ref> to emit TypeScript types from your schema for a type-safe client.
  • Storage - S3-compatible buckets for files (images, PDFs) with bucket policies analogous to RLS.
  • Realtime - Subscribe to insert/update/delete on tables or channels for live UI updates.
  • Edge Functions - Deno functions for webhooks, light API logic, or tasks that should not live in the database.
  • Local dev - supabase init and supabase start spin up local Postgres and services; useful for offline work, while cloud projects are fastest for a first tutorial.

Demo

Runnable scripts for this post live in the supabase-basics-demo folder in the private demos repository. Get access via code demos.