This workflow follows the Documentdefaultdataloader → OpenAI Embeddings 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 →
{
"name": "01 \u2014 Ingest NIST CSF 2.0",
"settings": {
"executionOrder": "v1"
},
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "ingest-nist-csf",
"responseMode": "lastNode",
"options": {}
},
"id": "a1000000-0000-4000-8000-000000000001",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
-640,
0
],
"notes": "A webhook rather than a manual trigger so the run is reproducible from a script."
},
{
"parameters": {
"fileSelector": "/data/docs/NIST.CSWP.29.pdf",
"options": {}
},
"id": "a1000000-0000-4000-8000-000000000002",
"name": "Read PDF",
"type": "n8n-nodes-base.readWriteFile",
"typeVersion": 1,
"position": [
-420,
0
],
"notes": "Mounted read-only. Only this PDF \u2014 the other two stay unprocessed to control cost."
},
{
"parameters": {
"operation": "pdf",
"options": {}
},
"id": "a1000000-0000-4000-8000-000000000003",
"name": "Extract PDF Text",
"type": "n8n-nodes-base.extractFromFile",
"typeVersion": 1,
"position": [
-200,
0
]
},
{
"parameters": {
"mode": "insert",
"tableName": "documents",
"options": {
"queryName": "match_documents"
}
},
"id": "a1000000-0000-4000-8000-000000000004",
"name": "Supabase Vector Store",
"type": "@n8n/n8n-nodes-langchain.vectorStoreSupabase",
"typeVersion": 1.1,
"position": [
20,
0
],
"credentials": {
"supabaseApi": {
"name": "<your credential>"
}
},
"notes": "Table and query name must match sql/001_documents_and_match.sql."
},
{
"parameters": {
"model": "text-embedding-3-small",
"options": {}
},
"id": "a1000000-0000-4000-8000-000000000005",
"name": "Embeddings OpenAI",
"type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
"typeVersion": 1.2,
"position": [
-60,
220
],
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"notes": "1536 dimensions \u2014 pinned by the documents.embedding column width."
},
{
"parameters": {
"dataType": "json",
"jsonMode": "expressionData",
"jsonData": "={{ $json.text }}",
"textSplittingMode": "custom",
"options": {
"metadata": {
"metadataValues": [
{
"name": "source",
"value": "NIST.CSWP.29.pdf"
},
{
"name": "title",
"value": "NIST Cybersecurity Framework 2.0"
}
]
}
}
},
"id": "a1000000-0000-4000-8000-000000000006",
"name": "Default Data Loader",
"type": "@n8n/n8n-nodes-langchain.documentDefaultDataLoader",
"typeVersion": 1,
"position": [
120,
220
],
"notes": "dataType only accepts json or binary \u2014 there is no text mode. Feeding the extracted text through jsonData is what routes the PDF body to the custom splitter; the default (allInputData) hands the loader the whole item and it splits per line, producing ~99-character fragments."
},
{
"parameters": {
"chunkSize": 1000,
"chunkOverlap": 150,
"options": {}
},
"id": "a1000000-0000-4000-8000-000000000007",
"name": "Recursive Character Text Splitter",
"type": "@n8n/n8n-nodes-langchain.textSplitterRecursiveCharacterTextSplitter",
"typeVersion": 1,
"position": [
120,
420
]
},
{
"parameters": {
"operation": "getAll",
"tableId": "documents",
"returnAll": true,
"orderBy": "id.asc",
"filters": {}
},
"id": "a1000000-0000-4000-8000-000000000008",
"name": "Read Back Rows",
"type": "n8n-nodes-base.supabase",
"typeVersion": 1,
"position": [
280,
0
],
"credentials": {
"supabaseApi": {
"name": "<your credential>"
}
},
"notes": "executeOnce matters: without it this runs once per inserted chunk, and 187 full-table reads with 1536 floats per row is what tripped the task runner.",
"executeOnce": true
},
{
"parameters": {
"jsCode": "// Row count is exact here: executeOnce plus returnAll means one full read.\n// max(id) would be wrong after a reset \u2014 DELETE does not rewind the bigserial.\nconst rows = $input.all().map((r) => r.json);\nconst lengths = rows.map((r) => (r.content ?? '').length);\nconst first = rows[0] ?? {};\nconst embedding = typeof first.embedding === 'string' ? JSON.parse(first.embedding) : first.embedding;\nreturn [{ json: {\n rowCount: rows.length,\n embeddingDimensions: Array.isArray(embedding) ? embedding.length : null,\n chunkChars: { min: Math.min(...lengths), max: Math.max(...lengths), mean: Math.round(lengths.reduce((a,b)=>a+b,0)/lengths.length), total: lengths.reduce((a,b)=>a+b,0) },\n sampleChunk: (first.content ?? '').slice(0, 600),\n sampleMetadata: first.metadata ?? null,\n} }];"
},
"id": "a1000000-0000-4000-8000-000000000009",
"name": "Summarise",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
500,
0
],
"notes": "No executeOnce here: it would clamp the node to the first item and report a row count of 1."
}
],
"connections": {
"Webhook": {
"main": [
[
{
"node": "Read PDF",
"type": "main",
"index": 0
}
]
]
},
"Read PDF": {
"main": [
[
{
"node": "Extract PDF Text",
"type": "main",
"index": 0
}
]
]
},
"Extract PDF Text": {
"main": [
[
{
"node": "Supabase Vector Store",
"type": "main",
"index": 0
}
]
]
},
"Supabase Vector Store": {
"main": [
[
{
"node": "Read Back Rows",
"type": "main",
"index": 0
}
]
]
},
"Read Back Rows": {
"main": [
[
{
"node": "Summarise",
"type": "main",
"index": 0
}
]
]
},
"Embeddings OpenAI": {
"ai_embedding": [
[
{
"node": "Supabase Vector Store",
"type": "ai_embedding",
"index": 0
}
]
]
},
"Default Data Loader": {
"ai_document": [
[
{
"node": "Supabase Vector Store",
"type": "ai_document",
"index": 0
}
]
]
},
"Recursive Character Text Splitter": {
"ai_textSplitter": [
[
{
"node": "Default Data Loader",
"type": "ai_textSplitter",
"index": 0
}
]
]
}
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
openAiApisupabaseApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
01 — Ingest NIST CSF 2.0. Uses readWriteFile, vectorStoreSupabase, embeddingsOpenAi, documentDefaultDataLoader. Webhook trigger; 9 nodes.
Source: https://github.com/BhrayanM/rag-engine/blob/main/workflows/01-ingest-nist-csf.json — 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.
Bread-Meat-Delivery. Uses lmChatOpenAi, agent, httpRequest, redis. Webhook trigger; 91 nodes.
Hi! I’m Amanda, a creator of intelligent automations using n8n and Make. I’ve been building AI-powered workflows for over 2 years, always focused on usability and innovation. This one here is very spe
YouTube Agent. Uses supabase, agent, lmChatAnthropic, outputParserStructured. Webhook trigger; 56 nodes.
InsightsLM - Upsert to Vector Store. Uses vectorStoreSupabase, documentDefaultDataLoader, textSplitterRecursiveCharacterTextSplitter, embeddingsOpenAi. Webhook trigger; 17 nodes.
• Create a Google Drive folder to watch. • Connect your Google Drive account in n8n and authorize access. • Point the Google Drive Trigger node to this folder (new/modified files trigger the flow).