This workflow corresponds to n8n.io template #17563 — we link there as the canonical source.
This workflow follows the Agent → Chat Trigger recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"id": "NeT9JiytGlgek6g0",
"name": "supabase_storage_file_chat_agent",
"tags": [],
"nodes": [
{
"id": "21906a5e-6945-49d5-9031-798b881e8bbd",
"name": "Overview",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1584,
240
],
"parameters": {
"color": 7,
"width": 580,
"height": 1860,
"content": "## \ud83d\udcc1 Chat With Files in Supabase Storage\n\nA two-part workflow that keeps a Supabase vector store in sync with files sitting in Supabase Storage, then exposes an AI chat agent that answers questions using those files as its knowledge base. New files are automatically detected, downloaded, chunked, embedded, and indexed \u2014 no manual re-upload step required.\n\n**Perfect for:** teams who already store documents in Supabase Storage and want a chatbot that can answer questions grounded in that content, without wiring up a separate document pipeline.\n\n---\n\n## How it works\n\n**Sync scenario (manual trigger):**\n1. **When clicking 'Test workflow'** \u2014 Starts the sync run.\n2. **Get All Files** \u2014 Retrieves already-indexed file records from the Supabase `files` table.\n3. **Aggregate** \u2014 Collapses those records into one array for comparison.\n4. **Get All files** \u2014 Lists everything currently in the Supabase Storage `private` bucket.\n5. **Loop Over Items** \u2014 Processes each storage file one at a time.\n6. **If** \u2014 Passes through only files not yet indexed and not the `.emptyFolderPlaceholder` marker.\n7. **Download** \u2014 Fetches the new file's binary from Supabase Storage.\n8. **Switch** \u2014 Branches by file extension: no extension \u2192 `txt`, `.pdf` \u2192 PDF extraction.\n9. **Extract Document PDF** \u2014 Extracts text from PDF files. *(pdf branch only)*\n10. **Merge** \u2014 Converges the txt and PDF branches back into one stream.\n11. **Create File record2** \u2014 Logs the new file's name and storage ID into the `files` table.\n12. **Insert into Supabase Vectorstore** \u2014 Embeds and stores the file content in the `documents` table, then loops back for the next file.\n13. **Embeddings OpenAI** \u2014 Generates the embeddings used for indexing.\n14. **Default Data Loader** \u2014 Loads the file content, tagging each chunk with `file_id` metadata.\n15. **Recursive Character Text Splitter** \u2014 Splits content into 500-token chunks with 200-token overlap.\n\n**Chat scenario (chat trigger):**\n16. **When chat message received** \u2014 Opens a chat session. *(separate trigger)*\n17. **AI Agent** \u2014 Answers user questions using retrieval-augmented context.\n18. **OpenAI Chat Model1** \u2014 Powers the AI Agent's reasoning.\n19. **Vector Store Tool1** \u2014 A retrieval tool the agent calls (`knowledge_base`, top-8 results).\n20. **Supabase Vector Store** \u2014 Backs the retrieval tool, querying the `documents` table. *(hardcoded to one `file_id` in this template \u2014 see setup)*\n21. **Embeddings OpenAI2** \u2014 Generates query embeddings for retrieval.\n22. **OpenAI Chat Model2** \u2014 Composes the retrieval query for the Vector Store Tool.\n\n---\n\n## Setup (~20 minutes)\n\n1. **Supabase** \u2014 Add a Supabase API credential to *Get All Files*, *Get All files*, *Download*, *Create File record2*, *Insert into Supabase Vectorstore*, and *Supabase Vector Store*. Replace the hardcoded storage URL in *Get All files* and *Download* with your own Supabase project URL.\n2. **Supabase tables** \u2014 Create a `files` table (`name`, `storage_id`) and a `documents` table matching Supabase's standard `vectorStoreSupabase` schema with a `match_documents` query function.\n3. **OpenAI** \u2014 Add API keys to *Embeddings OpenAI*, *Embeddings OpenAI2*, *OpenAI Chat Model1*, and *OpenAI Chat Model2* \u2014 consolidate the three differently-named credentials shipped in this template into one.\n4. **Hardcoded `file_id` filter** \u2014 Remove or generalize the metadata filter on *Supabase Vector Store* (currently locked to one leftover test `file_id`) so the agent searches across all indexed documents.\n5. **Text file handling** \u2014 The Switch node's `txt` branch has no extraction node wired to it in this template; add one if you expect non-PDF uploads.\n> The **If** node's dedup check reads from `$('Aggregate').item.json.data` \u2014 keep that reference intact if you restructure the sync scenario, or new-file detection will break."
},
"typeVersion": 1
},
{
"id": "6d4a8067-a3c5-4743-ad6e-a957a855d9ce",
"name": "Section: Trigger & Dedup Check",
"type": "n8n-nodes-base.stickyNote",
"position": [
-912,
768
],
"parameters": {
"color": 5,
"width": 1064,
"height": 452,
"content": "## 1\ufe0f\u20e3 Trigger & Dedup Check\n\n**When clicking 'Test workflow'** starts the sync run. **Get All Files** pulls already-indexed records from Supabase and **Aggregate** collapses them into one array, while **Get All files** lists everything currently in storage. **Loop Over Items** walks that list one file at a time, and **If** filters out files that are already indexed or are empty-folder placeholders."
},
"typeVersion": 1
},
{
"id": "26efb1ba-c9a5-4aa6-8177-af2c45be2b6f",
"name": "Section: Download & Extraction",
"type": "n8n-nodes-base.stickyNote",
"position": [
176,
768
],
"parameters": {
"color": 3,
"width": 872,
"height": 456,
"content": "## 2\ufe0f\u20e3 Download & Extraction\n\n**Download** fetches the new file's binary from Supabase Storage, and **Switch** routes it by extension \u2014 plain files are treated as text while **Extract Document PDF** pulls text out of PDFs. Both paths converge at **Merge** before moving on to indexing."
},
"typeVersion": 1
},
{
"id": "6bdc02e7-94fd-4cab-aa34-e6e9e0712d1d",
"name": "Section: Indexing Pipeline",
"type": "n8n-nodes-base.stickyNote",
"position": [
1072,
704
],
"parameters": {
"color": 6,
"width": 600,
"height": 736,
"content": "## 3\ufe0f\u20e3 Indexing Pipeline\n\n**Create File record2** logs the new file into the `files` table, then **Insert into Supabase Vectorstore** embeds and stores its content in the `documents` table. **Embeddings OpenAI** generates the vectors, **Default Data Loader** loads the content with `file_id` metadata, and **Recursive Character Text Splitter** chunks it into 500-token pieces before the loop moves to the next file."
},
"typeVersion": 1
},
{
"id": "15316395-b084-4791-a7ff-de60e54aecd0",
"name": "Section: AI Chat Agent",
"type": "n8n-nodes-base.stickyNote",
"position": [
32,
-176
],
"parameters": {
"color": 4,
"width": 908,
"height": 804,
"content": "## 4\ufe0f\u20e3 AI Chat Agent\n\n**When chat message received** opens a chat session for the **AI Agent**, which reasons with **OpenAI Chat Model1** and calls **Vector Store Tool1** to search the knowledge base. That tool is backed by **Supabase Vector Store**, using **Embeddings OpenAI2** for query embeddings and **OpenAI Chat Model2** for query composition."
},
"typeVersion": 1
},
{
"id": "50b4fdfa-ba6e-4de9-94d5-4ea00c796c5e",
"name": "Get All files",
"type": "n8n-nodes-base.httpRequest",
"position": [
-272,
928
],
"parameters": {
"url": "=https://yqtvdcvjboenlblgcivl.supabase.co/storage/v1/object/list/private",
"method": "POST",
"options": {},
"jsonBody": "={\n \"prefix\": \"\",\n \"limit\": 100,\n \"offset\": 0,\n \"sortBy\": {\n \"column\": \"name\",\n \"order\": \"asc\"\n }\n}",
"sendBody": true,
"specifyBody": "json",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "supabaseApi"
},
"typeVersion": 4.2
},
{
"id": "e3fbd6b1-181f-48aa-b26c-b927466f8d63",
"name": "Default Data Loader",
"type": "@n8n/n8n-nodes-langchain.documentDefaultDataLoader",
"position": [
1152,
1120
],
"parameters": {
"options": {
"metadata": {
"metadataValues": [
{
"name": "=file_id",
"value": "={{ $json.id }}"
}
]
}
},
"jsonData": "={{ $('Merge').item.json.data ?? $('Merge').item.json.text }}",
"jsonMode": "expressionData"
},
"typeVersion": 1
},
{
"id": "5cc47c58-feb0-424d-94f3-4d37f25deb8d",
"name": "Recursive Character Text Splitter",
"type": "@n8n/n8n-nodes-langchain.textSplitterRecursiveCharacterTextSplitter",
"position": [
1152,
1296
],
"parameters": {
"options": {},
"chunkSize": 500,
"chunkOverlap": 200
},
"typeVersion": 1
},
{
"id": "cf5cf8c0-b291-4c49-8ea7-e0a480f74456",
"name": "Extract Document PDF",
"type": "n8n-nodes-base.extractFromFile",
"position": [
592,
1024
],
"parameters": {
"options": {},
"operation": "pdf"
},
"typeVersion": 1,
"alwaysOutputData": false
},
{
"id": "e9aeda1d-b84b-4055-9ed9-843530849a2b",
"name": "Embeddings OpenAI",
"type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
"position": [
912,
1104
],
"parameters": {
"model": "text-embedding-3-small",
"options": {}
},
"typeVersion": 1
},
{
"id": "a9237f25-df2f-49b9-9584-189a31d30f5a",
"name": "Create File record2",
"type": "n8n-nodes-base.supabase",
"position": [
896,
928
],
"parameters": {
"tableId": "files",
"fieldsUi": {
"fieldValues": [
{
"fieldId": "name",
"fieldValue": "={{ $('Loop Over Items').item.json.name }}"
},
{
"fieldId": "storage_id",
"fieldValue": "={{ $('Loop Over Items').item.json.id }}"
}
]
}
},
"typeVersion": 1
},
{
"id": "643b5fe2-d5c3-4d7a-a412-d5b88fe5a65e",
"name": "If",
"type": "n8n-nodes-base.if",
"position": [
48,
928
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "9b14e306-a04d-40f7-bc5b-b8eda8d8f7f2",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ \n !$('Aggregate').item.json.data || \n !Array.isArray($('Aggregate').item.json.data) || \n !$('Aggregate').item.json.data.some(item => \n item.storage_id === $('Loop Over Items').item.json.id \n ) \n}}",
"rightValue": ""
},
{
"id": "c3c0af88-9aea-4539-8948-1b69e601c27c",
"operator": {
"type": "string",
"operation": "notEquals"
},
"leftValue": "={{ $json.name }}",
"rightValue": ".emptyFolderPlaceholder"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "526f5b5d-41b1-4e12-a6a1-3eab763d1dfd",
"name": "Get All Files",
"type": "n8n-nodes-base.supabase",
"position": [
-656,
928
],
"parameters": {
"tableId": "files",
"operation": "getAll"
},
"typeVersion": 1,
"alwaysOutputData": true
},
{
"id": "1b83a9ad-39b6-4b48-aee1-ef1f9b7a21f3",
"name": "Download",
"type": "n8n-nodes-base.httpRequest",
"position": [
256,
928
],
"parameters": {
"url": "=https://yqtvdcvjboenlblgcivl.supabase.co/storage/v1/object/private/{{ $json.name }}",
"options": {},
"authentication": "predefinedCredentialType",
"nodeCredentialType": "supabaseApi"
},
"typeVersion": 4.2
},
{
"id": "aec17e20-a3fb-48a6-aa1f-55d7ad3f3b03",
"name": "Loop Over Items",
"type": "n8n-nodes-base.splitInBatches",
"position": [
-112,
928
],
"parameters": {
"options": {},
"batchSize": "=1"
},
"typeVersion": 3
},
{
"id": "77859d96-b8b9-411e-b30c-38922580170d",
"name": "When clicking \u2018Test workflow\u2019",
"type": "n8n-nodes-base.manualTrigger",
"position": [
-832,
928
],
"parameters": {},
"typeVersion": 1
},
{
"id": "b2c058ec-a52d-4010-bade-29742fbd424e",
"name": "Aggregate",
"type": "n8n-nodes-base.aggregate",
"position": [
-448,
928
],
"parameters": {
"options": {},
"aggregate": "aggregateAllItemData"
},
"typeVersion": 1,
"alwaysOutputData": true
},
{
"id": "6c43c4d0-3d41-43ad-bfe1-5a31b5027b8f",
"name": "When chat message received",
"type": "@n8n/n8n-nodes-langchain.chatTrigger",
"position": [
160,
-16
],
"parameters": {
"options": {}
},
"typeVersion": 1.1
},
{
"id": "0fb2a277-011f-4711-a895-a506845401cf",
"name": "OpenAI Chat Model1",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
304,
192
],
"parameters": {
"options": {}
},
"typeVersion": 1
},
{
"id": "9e99f710-eccb-448e-9239-e46baddf32aa",
"name": "Embeddings OpenAI2",
"type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
"position": [
384,
480
],
"parameters": {
"model": "text-embedding-3-small",
"options": {}
},
"typeVersion": 1
},
{
"id": "cf322580-ade9-45d8-84e0-9fda5d7b341a",
"name": "OpenAI Chat Model2",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
672,
336
],
"parameters": {
"options": {}
},
"typeVersion": 1
},
{
"id": "115c0ceb-0314-4284-bd26-9b0d1a8992c7",
"name": "Vector Store Tool1",
"type": "@n8n/n8n-nodes-langchain.toolVectorStore",
"position": [
464,
192
],
"parameters": {
"name": "knowledge_base",
"topK": 8,
"description": "Retrieve data about user request"
},
"typeVersion": 1
},
{
"id": "6e99aad3-c6e7-48d9-9f1e-ff07f1c6b9d7",
"name": "Switch",
"type": "n8n-nodes-base.switch",
"position": [
416,
928
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "txt",
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{$binary.data?.fileExtension == undefined }}",
"rightValue": "txt"
}
]
},
"renameOutput": true
},
{
"outputKey": "pdf",
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "bf04cbec-dd86-4607-988f-4c96b6fd4b58",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{$binary.data.fileExtension }}",
"rightValue": "pdf"
}
]
},
"renameOutput": true
}
]
},
"options": {}
},
"typeVersion": 3.1
},
{
"id": "adc4fdfa-6bfc-404f-8925-ccb8f0c937c1",
"name": "Insert into Supabase Vectorstore",
"type": "@n8n/n8n-nodes-langchain.vectorStoreSupabase",
"position": [
1072,
912
],
"parameters": {
"mode": "insert",
"options": {
"queryName": "match_documents"
},
"tableName": {
"__rl": true,
"mode": "list",
"value": "documents",
"cachedResultName": "documents"
}
},
"typeVersion": 1
},
{
"id": "c305eacb-d8ef-458b-8ca5-9b088145b4e7",
"name": "Merge",
"type": "n8n-nodes-base.merge",
"position": [
736,
928
],
"parameters": {},
"typeVersion": 3
},
{
"id": "a8438217-36f6-4a57-b5fb-b8e5214e887a",
"name": "AI Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
384,
-16
],
"parameters": {
"options": {}
},
"typeVersion": 1.7
},
{
"id": "3bc30eed-23a2-496e-af85-cd4bbedbb3f8",
"name": "Supabase Vector Store",
"type": "@n8n/n8n-nodes-langchain.vectorStoreSupabase",
"position": [
384,
352
],
"parameters": {
"options": {
"metadata": {
"metadataValues": [
{
"name": "file_id",
"value": "300b0128-0955-4058-b0d3-a9aefe728432"
}
]
}
},
"tableName": {
"__rl": true,
"mode": "list",
"value": "documents",
"cachedResultName": "documents"
}
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"executionOrder": "v1"
},
"versionId": "2bd0c469-821e-40da-8a32-3f1a8e84fe0e",
"nodeGroups": [],
"connections": {
"If": {
"main": [
[
{
"node": "Download",
"type": "main",
"index": 0
}
],
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"Merge": {
"main": [
[
{
"node": "Create File record2",
"type": "main",
"index": 0
}
]
]
},
"Switch": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 0
}
],
[
{
"node": "Extract Document PDF",
"type": "main",
"index": 0
}
]
]
},
"Download": {
"main": [
[
{
"node": "Switch",
"type": "main",
"index": 0
}
]
]
},
"Aggregate": {
"main": [
[
{
"node": "Get All files",
"type": "main",
"index": 0
}
]
]
},
"Get All Files": {
"main": [
[
{
"node": "Aggregate",
"type": "main",
"index": 0
}
]
]
},
"Get All files": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"Loop Over Items": {
"main": [
[],
[
{
"node": "If",
"type": "main",
"index": 0
}
]
]
},
"Embeddings OpenAI": {
"ai_embedding": [
[
{
"node": "Insert into Supabase Vectorstore",
"type": "ai_embedding",
"index": 0
}
]
]
},
"Embeddings OpenAI2": {
"ai_embedding": [
[
{
"node": "Supabase Vector Store",
"type": "ai_embedding",
"index": 0
}
]
]
},
"OpenAI Chat Model1": {
"ai_languageModel": [
[
{
"node": "AI Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"OpenAI Chat Model2": {
"ai_languageModel": [
[
{
"node": "Vector Store Tool1",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Vector Store Tool1": {
"ai_tool": [
[
{
"node": "AI Agent",
"type": "ai_tool",
"index": 0
}
]
]
},
"Create File record2": {
"main": [
[
{
"node": "Insert into Supabase Vectorstore",
"type": "main",
"index": 0
}
]
]
},
"Default Data Loader": {
"ai_document": [
[
{
"node": "Insert into Supabase Vectorstore",
"type": "ai_document",
"index": 0
}
]
]
},
"Extract Document PDF": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 1
}
]
]
},
"Supabase Vector Store": {
"ai_vectorStore": [
[
{
"node": "Vector Store Tool1",
"type": "ai_vectorStore",
"index": 0
}
]
]
},
"When chat message received": {
"main": [
[
{
"node": "AI Agent",
"type": "main",
"index": 0
}
]
]
},
"Insert into Supabase Vectorstore": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"Recursive Character Text Splitter": {
"ai_textSplitter": [
[
{
"node": "Default Data Loader",
"type": "ai_textSplitter",
"index": 0
}
]
]
},
"When clicking \u2018Test workflow\u2019": {
"main": [
[
{
"node": "Get All Files",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow syncs files from Supabase Storage into a Supabase vector store using OpenAI embeddings, then exposes an n8n chat trigger where an AI agent answers questions by retrieving relevant document chunks from Supabase. Starts a manual sync run when you click “Test…
Source: https://n8n.io/workflows/17563/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Alfred (funcional). Uses gmailTool, googleCalendarTool, gmail, embeddingsOpenAi. Event-driven trigger; 83 nodes.
Your AI workforce is ready. Are you?
Agent IA Projet Client. Uses executeWorkflowTrigger, lmChatOpenAi, toolWorkflow, vectorStoreQdrant. Event-driven trigger; 79 nodes.
This intelligent chatbot leverages cutting-edge financial APIs and AI-driven analysis to deliver comprehensive stock research reports. Get instant access to professional-grade investment analysis that
This n8n template automatically classifies incoming emails (Sales, Support, Internal, Finance, Promotions) and routes them to a dedicated OpenAI LLM Agent for processing. Depending on the category, th