AI agents

RAG document ingest into Postgres pgvector in n8n

Reads Markdown files from a folder, splits them into 1000 character chunks with 200 of overlap, embeds them with OpenAI and inserts them into a pgvector table.

Trigger
Manual Trigger
Nodes
6
Requires
Postgres (with the pgvector extension), OpenAI
Category
AI agents
From the course
AI Agents in n8n
Published
2026-09-10

Node types used

  • Manual Trigger
  • Read/Write Files from Disk
  • Postgres PGVector Store
  • Embeddings OpenAI
  • Default Data Loader
  • Recursive Character Text Splitter
Workflow diagram: RAG document ingest into Postgres pgvector in n8nai_embeddingai_documentai_textSplitterWhen clicking Execute…When clicking Execute workflowRead handbook filesPostgres PGVector Sto…Postgres PGVector StoreDefault Data LoaderRecursive Character T…Recursive Character Text SplitterEmbeddings OpenAI
TriggerActionAI

What it does

An agent that answers from your own documents needs those documents in a shape it can search, which means chunked, embedded and stored in a vector table. That ingest step is where most retrieval setups quietly go wrong: chunks too large to be useful, no overlap so a sentence is cut in half, or a column layout the retrieval node cannot read back.

A Manual Trigger starts the run because ingest is something you do on purpose, not on a schedule. A Read/Write Files from Disk node reads every .md file matching /home/node/.n8n-files/docs/*.md and passes them on as binary items. Those go into a Postgres PGVector Store node in insert mode, writing to a table named docs with the column names spelled out explicitly: id, embedding, text and metadata. Three sub-nodes hang off it. A Default Data Loader takes the binary input with the text loader and custom splitting turned on. A Recursive Character Text Splitter feeds that loader with a chunk size of 1000 and an overlap of 200 characters. An OpenAI Embeddings node using text-embedding-3-small supplies the vectors, batched 200 at a time.

This is the ingest half only. There is no retrieval and no agent here: the companion workflow points a vector store tool at the same table and the same embedding model. The mode is insert, not upsert, so this workflow only ever adds rows.

Node by node

  1. 1

    When clicking Execute workflow A Manual Trigger. Ingest runs when you press the button, not on a schedule.

  2. 2

    Read handbook files Reads every file matching the selector /home/node/.n8n-files/docs/*.md from the n8n container filesystem and emits one binary item per file.

  3. 3

    Postgres PGVector Store Insert mode into the table docs, with embeddingBatchSize 200 and the column names set explicitly to id, embedding, text and metadata. Those four names have to match whatever the retrieval side expects.

  4. 4

    Default Data Loader Attached to the vector store on the ai_document connection. Data type binary, binary mode all input data, text loader, and text splitting set to custom so the splitter below it is used rather than the default.

  5. 5

    Recursive Character Text Splitter Attached to the loader on the ai_textSplitter connection. Chunk size 1000 characters with 200 characters of overlap, so a sentence split across a boundary still appears whole in one of the two chunks.

  6. 6

    Embeddings OpenAI Attached to the vector store on the ai_embedding connection. Uses text-embedding-3-small to turn each chunk into a vector.

Setup after import

  1. 1

    Run a Postgres with the pgvector extension available, create the docs table with an id, an embedding vector column, a text column and a jsonb metadata column, then create the vector extension in that database.

  2. 2

    Create a Postgres credential pointing at that database and select it on Postgres PGVector Store.

  3. 3

    Create an OpenAI credential and select it on Embeddings OpenAI.

  4. 4

    Put your documents where the file selector can see them. The export reads /home/node/.n8n-files/docs/*.md, which on Docker means a volume mounted into the n8n container.

  5. 5

    If you change the embedding model, empty the table first. Vectors from two different models cannot be compared.

Limits

  • Insert mode, not upsert. Running it twice on the same folder stores every chunk twice.

  • Markdown only, from one folder, with no recursion into subfolders.

  • No retrieval and no agent. This workflow only fills the table.

  • Embedding costs are per run and per chunk, and a large folder is a large bill.

  • Nothing tracks which file a run has already processed.

Download the workflow

The 6 node export as n8n reads it. Credential ids, personal values and real endpoints are replaced with placeholders, so nothing here can reach an account that is not yours. No email, no account.

Download n8n-rag-ingest-pgvector.json

Get help with this in the community

If the import fails, if a node errors on the first run, or if you want to point this at a service it does not cover yet, post it in the free House of Loops community. Say which template it is and paste the error. Shannon Atkinson answers, and the answer stays there for the next person who hits the same thing.

Ask in the community