Node-RED plugin

node-red-contrib-ollama

Add AI to your flows. A set of Node-RED nodes that wrap ollama.js, so you can chat, generate, and embed with any model — local Ollama or Ollama Cloud — without hand-rolling the client calls yourself.

v0.6.2MIT licenseNode.js ≥ 18
View on Node-RED LibraryView on GitHubView on npm

What it is

Ollama, as flow-native nodes

Instead of calling the Ollama API from a Function node, drop in a config node for your server and wire up dedicated nodes for chat, generation, embeddings and model management. Every node mirrors an ollama.js client call, with per-call parameters resolvable from either the node's own configuration or an incoming msg.payload field.

Works with a local Ollama install, or with Ollama Cloud using an API key — same nodes, same flows.

Requirements

Before you start

Installation

Two ways to install

Node-RED editor

  1. Menu → Manage palette
  2. Go to the Install tab
  3. Search for node-red-contrib-ollama
  4. Click Install

Command line

From your Node-RED user directory:

npm install node-red-contrib-ollama

Restart Node-RED to load the new nodes.

Configuration

Point it at a server

Every action node connects through a shared Server config node.

Local Ollama

Host: localhost (or your server's address)
Port: 11434

Ollama Cloud

Check "Use Ollama Cloud" and paste an API key — host/port are set automatically.

Nodes

Config nodes

Server

Connection to a local Ollama instance or Ollama Cloud (host, port, API key).

Options

Reusable generation options (temperature, context size, and more).

Format

Reusable response format / JSON schema definition.

Tools

Reusable tool/function definitions for tool-calling models.

Action nodes

Chat

Generate the next message in a chat with a provided model.

Generate

Generate a response for a given prompt with a provided model.

Embed

Generate embeddings from a model.

List

List models that are available.

Show

Show details, template, parameters, license and system prompt of a model.

Ps

List models that are currently loaded into memory.

Pull

Download a model from the Ollama library.

Push

Upload a model to a model library.

Create

Create a model from a Modelfile.

Copy

Copy a model to a new name.

Delete

Delete a model and its data.

Abort

Abort all streamed generations currently running.

Examples

Examples

Node-RED wires the logic — these nodes replace the ollama.js client calls you'd otherwise write by hand.

Chat

Session-aware support chatbot

A webhook keeps a running conversation per visitor in flow context: build the message history, get a reply from Ollama, remember it for next time, and answer back over HTTP.

Scroll or pinch to zoom, drag to pan.

View flow JSON
[
  {
    "id": "tab1",
    "type": "tab",
    "label": "Flow 1",
    "disabled": false,
    "info": "",
    "env": []
  },
  {
    "id": "srv1",
    "type": "ollama-config-server",
    "name": "Local Ollama",
    "host": "localhost",
    "port": 11434,
    "useCloud": false
  },
  {
    "id": "n1",
    "type": "http in",
    "name": "POST /chat",
    "url": "/chat",
    "method": "post",
    "upload": false,
    "swaggerDoc": "",
    "x": 90,
    "y": 110,
    "wires": [
      [
        "n2"
      ]
    ],
    "z": "tab1"
  },
  {
    "id": "n2",
    "type": "function",
    "name": "Build messages",
    "func": "const sessionId = (msg.req && msg.req.headers['x-session-id']) || 'default';\nconst history = flow.get('chat_' + sessionId) || [];\nconst userText = (msg.req && msg.req.body && msg.req.body.message) || '';\nmsg.sessionId = sessionId;\nmsg.userText = userText;\nmsg.payload = {\n    model: 'llama3.2',\n    messages: history.concat([{ role: 'user', content: userText }])\n};\nreturn msg;",
    "outputs": 1,
    "timeout": 0,
    "noerr": 0,
    "initialize": "",
    "finalize": "",
    "libs": [],
    "x": 300,
    "y": 110,
    "wires": [
      [
        "n3"
      ]
    ],
    "z": "tab1"
  },
  {
    "id": "n3",
    "type": "ollama-chat",
    "name": "Chat",
    "server": "srv1",
    "x": 510,
    "y": 110,
    "wires": [
      [
        "n4"
      ]
    ],
    "z": "tab1"
  },
  {
    "id": "n4",
    "type": "function",
    "name": "Save history",
    "func": "const reply = msg.payload.message;\nconst history = flow.get('chat_' + msg.sessionId) || [];\nhistory.push({ role: 'user', content: msg.userText });\nhistory.push(reply);\nflow.set('chat_' + msg.sessionId, history);\nmsg.payload = { reply: reply.content };\nreturn msg;",
    "outputs": 1,
    "timeout": 0,
    "noerr": 0,
    "initialize": "",
    "finalize": "",
    "libs": [],
    "x": 720,
    "y": 110,
    "wires": [
      [
        "n5"
      ]
    ],
    "z": "tab1"
  },
  {
    "id": "n5",
    "type": "http response",
    "name": "Reply",
    "statusCode": "",
    "headers": {},
    "x": 930,
    "y": 110,
    "wires": [],
    "z": "tab1"
  }
]
Generate

Ticket triage & escalation

Incoming support tickets are acknowledged immediately, then a prompt built from the ticket's subject and body asks Ollama for a one-sentence triage summary — replies flagged urgent get routed to Slack, everything else is just logged.

Scroll or pinch to zoom, drag to pan.

View flow JSON
[
  {
    "id": "tab1",
    "type": "tab",
    "label": "Flow 1",
    "disabled": false,
    "info": "",
    "env": []
  },
  {
    "id": "srv2",
    "type": "ollama-config-server",
    "name": "Local Ollama",
    "host": "localhost",
    "port": 11434,
    "useCloud": false
  },
  {
    "id": "n1",
    "type": "http in",
    "name": "POST /tickets",
    "url": "/tickets",
    "method": "post",
    "upload": false,
    "swaggerDoc": "",
    "x": 90,
    "y": 130,
    "wires": [
      [
        "n2",
        "n8"
      ]
    ],
    "z": "tab1"
  },
  {
    "id": "n8",
    "type": "function",
    "name": "Acknowledge",
    "func": "msg.payload = { status: 'queued' };\nreturn msg;",
    "outputs": 1,
    "timeout": 0,
    "noerr": 0,
    "initialize": "",
    "finalize": "",
    "libs": [],
    "x": 300,
    "y": 210,
    "wires": [
      [
        "n9"
      ]
    ],
    "z": "tab1"
  },
  {
    "id": "n9",
    "type": "http response",
    "name": "Accepted",
    "statusCode": "202",
    "headers": {},
    "x": 510,
    "y": 210,
    "wires": [],
    "z": "tab1"
  },
  {
    "id": "n2",
    "type": "function",
    "name": "Build prompt",
    "func": "const ticket = (msg.req && msg.req.body) || {};\nconst subject = ticket.subject || '(no subject)';\nconst body = ticket.body || '';\nmsg.payload = {\n    model: 'llama3.2',\n    prompt: 'You triage support tickets. Reply with a one-sentence summary, and include the ' +\n        'word URGENT if this needs immediate attention.\\n\\nSubject: ' + subject + '\\nBody: ' + body\n};\nreturn msg;",
    "outputs": 1,
    "timeout": 0,
    "noerr": 0,
    "initialize": "",
    "finalize": "",
    "libs": [],
    "x": 300,
    "y": 130,
    "wires": [
      [
        "n3"
      ]
    ],
    "z": "tab1"
  },
  {
    "id": "n3",
    "type": "ollama-generate",
    "name": "Generate",
    "server": "srv2",
    "x": 510,
    "y": 130,
    "wires": [
      [
        "n4"
      ]
    ],
    "z": "tab1"
  },
  {
    "id": "n4",
    "type": "switch",
    "name": "Urgent?",
    "property": "payload.response",
    "propertyType": "msg",
    "rules": [
      {
        "t": "cont",
        "v": "URGENT",
        "vt": "str"
      },
      {
        "t": "else"
      }
    ],
    "checkall": "true",
    "repair": false,
    "outputs": 2,
    "x": 720,
    "y": 130,
    "wires": [
      [
        "n5"
      ],
      [
        "n7"
      ]
    ],
    "z": "tab1"
  },
  {
    "id": "n5",
    "type": "function",
    "name": "Format Slack message",
    "func": "msg.payload = { text: '🚨 ' + msg.payload.response };\nreturn msg;",
    "outputs": 1,
    "timeout": 0,
    "noerr": 0,
    "initialize": "",
    "finalize": "",
    "libs": [],
    "x": 930,
    "y": 70,
    "wires": [
      [
        "n6"
      ]
    ],
    "z": "tab1"
  },
  {
    "id": "n6",
    "type": "http request",
    "name": "Notify Slack",
    "method": "POST",
    "ret": "txt",
    "paytoqs": "ignore",
    "url": "https://hooks.slack.com/services/REPLACE/ME",
    "tls": "",
    "persist": false,
    "proxy": "",
    "insecureHTTPParser": false,
    "authType": "",
    "senderr": false,
    "headers": [],
    "x": 1140,
    "y": 70,
    "wires": [
      []
    ],
    "z": "tab1"
  },
  {
    "id": "n7",
    "type": "debug",
    "name": "Log ticket",
    "active": true,
    "tosidebar": true,
    "console": false,
    "tostatus": false,
    "complete": "payload",
    "targetType": "msg",
    "statusVal": "",
    "statusType": "auto",
    "x": 930,
    "y": 195,
    "wires": [],
    "z": "tab1"
  }
]
Embed

Index new documents for search

Read a file's contents, embed them, and append the vector to a flat-file store, ready for semantic search later — swap the manual trigger for a file-watch node to run it automatically.

Scroll or pinch to zoom, drag to pan.

View flow JSON
[
  {
    "id": "tab1",
    "type": "tab",
    "label": "Flow 1",
    "disabled": false,
    "info": "",
    "env": []
  },
  {
    "id": "srv3",
    "type": "ollama-config-server",
    "name": "Local Ollama",
    "host": "localhost",
    "port": 11434,
    "useCloud": false
  },
  {
    "id": "n1",
    "type": "inject",
    "name": "New file",
    "props": [
      {
        "p": "payload"
      },
      {
        "p": "filename",
        "v": "/tmp/example.txt",
        "vt": "str"
      }
    ],
    "repeat": "",
    "crontab": "",
    "once": false,
    "onceDelay": 0.1,
    "topic": "",
    "payload": "",
    "payloadType": "date",
    "x": 90,
    "y": 110,
    "wires": [
      [
        "n2"
      ]
    ],
    "z": "tab1"
  },
  {
    "id": "n2",
    "type": "file in",
    "name": "Read file",
    "filename": "filename",
    "filenameType": "msg",
    "format": "utf8",
    "chunk": false,
    "sendError": false,
    "encoding": "none",
    "allProps": false,
    "x": 300,
    "y": 110,
    "wires": [
      [
        "n3"
      ]
    ],
    "z": "tab1"
  },
  {
    "id": "n3",
    "type": "function",
    "name": "Build embed request",
    "func": "msg.text = msg.payload;\nmsg.payload = { model: 'all-minilm', input: msg.payload };\nreturn msg;",
    "outputs": 1,
    "timeout": 0,
    "noerr": 0,
    "initialize": "",
    "finalize": "",
    "libs": [],
    "x": 510,
    "y": 110,
    "wires": [
      [
        "n4"
      ]
    ],
    "z": "tab1"
  },
  {
    "id": "n4",
    "type": "ollama-embed",
    "name": "Embed",
    "server": "srv3",
    "x": 720,
    "y": 110,
    "wires": [
      [
        "n5"
      ]
    ],
    "z": "tab1"
  },
  {
    "id": "n5",
    "type": "function",
    "name": "Build vector record",
    "func": "msg.payload = JSON.stringify({\n    id: Date.now(),\n    text: msg.text,\n    embedding: msg.payload.embeddings[0]\n});\nreturn msg;",
    "outputs": 1,
    "timeout": 0,
    "noerr": 0,
    "initialize": "",
    "finalize": "",
    "libs": [],
    "x": 930,
    "y": 110,
    "wires": [
      [
        "n6"
      ]
    ],
    "z": "tab1"
  },
  {
    "id": "n6",
    "type": "file",
    "name": "Append to store",
    "filename": "/tmp/vector-store.jsonl",
    "filenameType": "str",
    "appendNewline": true,
    "createDir": true,
    "overwriteFile": "false",
    "encoding": "none",
    "x": 1140,
    "y": 110,
    "wires": [],
    "z": "tab1"
  }
]

Support the project

Like using it?

This is a free, open-source project maintained in spare time. If it's useful to you, a star or a sponsorship goes a long way.

♥ Sponsor on GitHub★ Star the repo