Connecting n8n to Supabase: the complete guide (auth, queries, vectors)
Published 18 July 2026 · 4 min read

Supabase is the most profitable backend to know when you automate with n8n: managed Postgres, an auto-generated REST API, built-in authentication and pgvector for AI — all with a generous free tier. This guide covers the four ways to wire it to n8n: the Supabase node for CRUD, the auth API for managing users, RPC for Postgres functions, and vectors for RAG.
1. The credential: service_role, and why
In n8n: Credentials → New → Supabase API. Two fields:
- Host: the project URL,
https://your-project.supabase.co(under Project Settings → API); - Service Role Secret: the
service_rolekey — not theanonkey.
Why service_role? Because n8n is a trusted backend: your workflows need to read and write without being blocked by Row Level Security. Immediate corollary: this key bypasses all your RLS policies. It must never appear client-side, nor in a webhook response sent back to a browser. When a workflow must act on behalf of a specific user, skip the Supabase node and call the REST API with the user's JWT (section 3).
2. CRUD: the Supabase node day to day
Example table — incoming leads to enrich:
create table leads (
id uuid primary key default gen_random_uuid(),
email text not null unique,
source text,
score int,
processed boolean default false,
created_at timestamptz default now()
);
The four operations of the Supabase node (resource Row):
- Create: map the columns (
email,source) from the previous node's data. Trap: a uniqueness violation (duplicate email) fails the item — enable Settings → On Error → Continue if duplicates are a normal case. - Get Many: tick Use Custom Filters for PostgREST syntax. Real example — unprocessed leads with a score of at least 60:
processed=eq.false&score=gte.60&order=created_at.desc&limit=20. - Update: filter
id=eq.{{ $json.id }}, then the columns to change (processed→true). Without a filter, PostgREST refuses — that is your safety net against an accidental global update. - Delete: same filter logic. Often prefer an
archived=trueupdate: a workflow mass-deleting on a badly written filter is unforgiving.
The PostgREST operators worth knowing: eq, neq, gt/gte, lt/lte, like.*pattern*, ilike (case-insensitive), in.(a,b,c), is.null.
3. Auth: creating and signing in users from n8n
The Supabase node does not handle authentication — that is the GoTrue API's job, called with an HTTP Request node. Three calls cover the essentials.
Create a user (as admin, with the service_role key):
POST https://your-project.supabase.co/auth/v1/admin/users
Headers:
apikey: <service_role>
Authorization: Bearer <service_role>
Body (JSON):
{ "email": "client@example.com", "password": "a-strong-password",
"email_confirm": true }
Sign a user in (get their JWT):
POST https://your-project.supabase.co/auth/v1/token?grant_type=password
Headers:
apikey: <anon>
Content-Type: application/json
Body (JSON):
{ "email": "client@example.com", "password": "a-strong-password" }
The response contains access_token: the user's JWT, valid for one hour.
Query as the user — this is where RLS kicks back in. Call the REST API with the JWT instead of the service_role key:
GET https://your-project.supabase.co/rest/v1/leads?select=*
Headers:
apikey: <anon>
Authorization: Bearer {{ $json.access_token }}
With an RLS policy like this one, each user only sees their own rows — even through n8n:
alter table leads enable row level security;
create policy "users see their own leads"
on leads for select
using (auth.uid() = owner_id);
4. RPC: calling your Postgres functions
Every Postgres function is exposed at /rest/v1/rpc/<name>. It is the bridge between n8n and your SQL logic — including match_documents, the vector similarity function used by RAG:
POST https://your-project.supabase.co/rest/v1/rpc/match_documents
Headers:
apikey: <service_role>
Authorization: Bearer <service_role>
Content-Type: application/json
Body (JSON):
{ "query_embedding": [0.0123, -0.0456, ...],
"match_count": 4,
"filter": { "source": "product-faq" } }
Useful when you want vector search without the LangChain nodes — for instance to return raw passages from an API.
5. Vectors: pgvector and the Supabase Vector Store node
For RAG, n8n ships a dedicated node, Supabase Vector Store, which reuses the same credential and expects the documents table + the match_documents function (the full SQL script is in our step-by-step pgvector guide). Three modes to remember:
- Insert Documents: ingestion (chunks + embeddings);
- Retrieve Documents (As Vector Store): retrieval inside a chain;
- Retrieve Documents (As Tool for AI Agent): the vector store becomes a tool the AI Agent decides to query — the mode our chatbot uses, including on WhatsApp.
Golden rule: the same embedding model at ingestion and retrieval time, and a consistent column dimension (vector(1536) for text-embedding-3-small).
6. When the API is not enough: the Postgres node
Complex joins, aggregations, insert ... on conflict, migrations: switch to the Postgres node with a direct connection. Under Project Settings → Database, take the transaction-mode pooler connection string (port 6543) — n8n workflows open and close connections in bursts, and the pooler is built for that. Keep port 5432 (session mode) for operations that require it (listen/notify, prepared statements).
Going further
You now have the four doors into Supabase from n8n. The logical next step: the complete pgvector guide to build the vector side end to end, then the RAG Assistant Pack (€119) — PDF ingestion, citations chatbot, Notion sync and the /ask API, four n8n workflows on Supabase, tested, documented, ready to import.
FAQ
Frequently asked questions
Which Supabase key should I use in n8n: anon or service_role?
The Supabase node credential expects the service_role key: n8n is a trusted backend and usually needs to write everywhere. Careful, this key bypasses Row Level Security — never expose it client-side, and if a workflow must act on behalf of a user, call the REST API with that user's JWT via an HTTP Request node instead.
Supabase node or Postgres node: which one should I pick?
The Supabase node goes through the REST API (PostgREST): perfect for simple CRUD, filters included, with no connection pool to manage. The Postgres node connects directly to the database (via the pooler, port 6543 in transaction mode): essential for raw SQL, complex joins, aggregations and migrations.
How do I call a Postgres function (RPC) from n8n?
The Supabase node does not cover RPC: use an HTTP Request node with a POST to https://your-project.supabase.co/rest/v1/rpc/function_name, with the apikey and Authorization: Bearer headers and the function arguments in the JSON body. That is how you call match_documents outside the vector nodes.
Is Supabase's free tier enough for n8n in production?
For reasonable internal use, yes: 500 MB database, pgvector included, REST API with generous limits. Its real constraints: the database pauses after 7 days of inactivity (a scheduled n8n workflow that pings it daily avoids this) and there are no automatic backups — move to the Pro plan as soon as the data matters.
RAG Assistant Pack
€119