n8n-binary-and-data
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinesen8n Binary and Data
n8n 二进制与数据
Every n8n item carries two independent slots: for structured data and for file bytes. They travel side by side through the workflow. File contents — the actual PDF, image, or zip — live in , never in . Get that split wrong and you read an empty field, lose a file mid-flow, or hand an AI agent a tool input it can't use.
$json$binary$binary$jsonThis skill covers where binary lives, how to read and write it, how to keep it from being silently stripped, the hard wall between binary and the AI-agent tool boundary, and why chat surfaces need a URL instead of raw bytes.
每个n8n条目都包含两个独立的存储区:用于结构化数据,用于文件字节。它们在工作流中并行传递。文件内容——实际的PDF、图片或压缩包——存储在中,绝不会出现在里。如果混淆了这两者,你会读取到空字段、在工作流中途丢失文件,或是给AI Agent传递无法使用的工具输入。
$json$binary$binary$json本技能涵盖了二进制数据的存储位置、读写方法、如何防止其被静默移除、二进制数据与AI Agent工具边界的严格限制,以及为何聊天界面需要URL而非原始字节。
The three rules that prevent 90% of binary bugs
避免90%二进制错误的三条规则
-
File contents are in, not
$binary. After an HTTP download, a "Read Files", or an email-attachment trigger, the bytes sit in$json.$binary.<key>holds metadata at most. Reading$jsonfor file contents gives you nothing.$json.data -
Binary cannot cross the AI-agent tool boundary — in either direction. Tool arguments and tool return values are JSON only. An uploaded image can't be passed into a tool as a file, and a tool can't return raw bytes. Pre-stage to storage and pass a key or URL through JSON instead. See.
AGENT_TOOL_BINARY.md -
Chat surfaces render images by URL, not by. Slack, Discord, Teams, Telegram, embedded webhook chat — none of them read the binary slot. The image has to live somewhere a URL can fetch it. See
$binary.CDN_REQUIREMENT.md
-
文件内容存储在中,而非
$binary。 在HTTP下载、“读取文件”或邮件附件触发后,字节数据会存放在$json中。$binary.<key>最多仅包含元数据。读取$json获取文件内容只会得到空值。$json.data -
二进制数据无法跨越AI Agent工具边界——无论方向如何。 工具参数和返回值仅支持JSON格式。上传的图片无法作为文件传入工具,工具也无法返回原始字节数据。应先将数据预存到存储服务中,再通过JSON传递密钥或URL。详见。
AGENT_TOOL_BINARY.md -
聊天界面通过URL渲染图片,而非。 Slack、Discord、Teams、Telegram、嵌入式webhook聊天——这些平台都不会读取二进制存储区。图片必须存储在可通过URL访问的位置。详见
$binary。CDN_REQUIREMENT.md
The two slots
两个存储区
Each item is shaped like this:
json
{
"json": { "customerId": 42, "status": "sent" },
"binary": {
"invoice": {
"data": "<base64-encoded bytes>",
"mimeType": "application/pdf",
"fileName": "invoice-42.pdf",
"fileExtension": "pdf"
}
}
}The key inside ( here) is the binary property name. Most file-handling nodes have a parameter that points at it — the producer names the slot, the consumer references it by that name. The default key across most nodes is , so when nothing tells you otherwise, assume .
binaryinvoicebinaryPropertyNamedata$binary.data$json$binary{{ $binary.invoice.fileName }}{{ $json.customerId }}This split also explains a webhook gotcha: a Webhook trigger receiving puts the uploaded file in and the accompanying form fields in — so an uploaded file is not somewhere under at all. (The nesting for webhooks is n8n-expression-syntax territory.)
multipart/form-data$binary$json.body$json$json.bodySee for the full slot anatomy, mime types, and size limits.
BINARY_BASICS.md每个条目的结构如下:
json
{
"json": { "customerId": 42, "status": "sent" },
"binary": {
"invoice": {
"data": "<base64-encoded bytes>",
"mimeType": "application/pdf",
"fileName": "invoice-42.pdf",
"fileExtension": "pdf"
}
}
}binaryinvoicebinaryPropertyNamedata$binary.data$json$binary{{ $binary.invoice.fileName }}{{ $json.customerId }}这种区分也解释了webhook的一个陷阱:接收的Webhook触发器会将上传的文件放入,将附带的表单字段放入——因此上传的文件根本不在下。(webhook的嵌套属于n8n-expression-syntax范畴。)
multipart/form-data$binary$json.body$json$json.body有关存储区完整结构、MIME类型和大小限制,请参阅。
BINARY_BASICS.mdProducing binary
生成二进制数据
You rarely build a slot by hand — nodes populate it for you:
$binary| Source | How binary appears |
|---|---|
HTTP Request with | Response body lands in |
| Read/Write Files from Disk | File contents read into |
| Storage downloads (S3, Google Drive, Dropbox, etc.) | Downloaded file in |
| Email triggers with attachments | Each attachment arrives in |
| Provider AI media nodes (image/audio gen) | Set |
For an HTTP download, the one field that matters is . Confirm it with on — leaving it as the default JSON/string format is the classic reason a downloaded file ends up as garbled text in instead of clean bytes in .
responseFormatget_nodenodes-base.httpRequest$json$binary你很少需要手动构建存储区——节点会自动为你填充:
$binary| 来源 | 二进制数据的呈现方式 |
|---|---|
设置 | 响应体存入 |
| 从磁盘读取/写入文件 | 文件内容读取到 |
| 存储服务下载(S3、Google Drive、Dropbox等) | 下载的文件存入 |
| 带附件的邮件触发器 | 每个附件都存入 |
| 供应商AI媒体节点(图像/音频生成) | 设置 |
对于HTTP下载,关键字段是。请通过查看的设置——若保留默认的JSON/字符串格式,下载的文件会以乱码文本形式出现在中,而非干净的字节数据存入,这是典型错误。
responseFormatget_nodenodes-base.httpRequest$json$binaryReading and writing binary in a Code node
在Code节点中读写二进制数据
Most workflows never need to crack open the bytes — they just pass binary through to a consumer (email attachment, file upload, Slack file). When you do need the raw bytes, do it in a Code node.
Read with — do not try to base64-decode by hand:
getBinaryDataBuffer$binary.<key>.datajavascript
// Code node, "Run Once for Each Item"
const buffer = await this.helpers.getBinaryDataBuffer(0, 'data'); // (itemIndex, propertyName)
const text = buffer.toString('utf-8');
const length = buffer.length;
return [{
json: { ...$json, length },
binary: $input.item.binary, // pass the binary through, or it's gone
}];Write by building the slot yourself — base64 the bytes plus a mime type and file name:
javascript
const text = 'Hello, world!';
return [{
json: { ok: true },
binary: {
report: {
data: Buffer.from(text).toString('base64'),
mimeType: 'text/plain',
fileName: 'report.txt',
fileExtension: 'txt',
},
},
}];The Code-node sandbox, helpers, and execution modes are the domain of n8n-code-javascript (and n8n-code-python) — use those for the language-level detail. The one binary-specific thing to remember here: a Code node that returns without re-attaching silently drops the file. See .
[{ json: {...} }]binaryBINARY_BASICS.md大多数工作流无需直接处理字节数据——只需将二进制数据传递给消费节点(邮件附件、文件上传、Slack文件)。当你确实需要原始字节数据时,请在Code节点中操作。
读取使用——请勿尝试手动对进行base64解码:
getBinaryDataBuffer$binary.<key>.datajavascript
// Code node, "Run Once for Each Item"
const buffer = await this.helpers.getBinaryDataBuffer(0, 'data'); // (itemIndex, propertyName)
const text = buffer.toString('utf-8');
const length = buffer.length;
return [{
json: { ...$json, length },
binary: $input.item.binary, // pass the binary through, or it's gone
}];写入需自行构建存储区——将字节数据进行base64编码,并添加MIME类型和文件名:
javascript
const text = 'Hello, world!';
return [{
json: { ok: true },
binary: {
report: {
data: Buffer.from(text).toString('base64'),
mimeType: 'text/plain',
fileName: 'report.txt',
fileExtension: 'txt',
},
},
}];Code节点的沙箱、辅助函数和执行模式属于n8n-code-javascript(以及n8n-code-python)的范畴——这些技能负责语言层面的细节。此处需要记住的二进制数据特定规则:若Code节点返回但未重新附加,则会静默丢失文件。详见。
[{ json: {...} }]binaryBINARY_BASICS.mdKeeping binary alive across transforms
在转换过程中保留二进制数据
JSON-only nodes — Edit Fields (Set), Code, IF, and others — can drop the slot from their output. The workflow validates clean and runs without error; the file just isn't there downstream when the email node goes to attach it.
$binaryTwo ways to keep it:
- Pass-through option on the transforming node. Edit Fields has ; a Code node can return
includeOtherFieldsexplicitly. Cheapest fix when it's available.binary: $input.item.binary - Fan out and Merge by position. Route the source into both the transform and a bypass branch, then recombine with a Merge in mode. The JSON comes from the transform side, the binary survives on the bypass side.
combineByPosition
[Source with binary] ─┬─→ [Edit Fields: change JSON] ─┐
│ (binary stripped here) ├─→ [Merge: combineByPosition] ─→ [Email: attach]
└──────────────────────────────────┘
(bypass — binary passes through untouched)combineByPositionMERGE_FOR_CONTEXT.md仅处理JSON的节点——编辑字段(设置)、Code、IF等——可能会从输出中移除存储区。工作流会正常验证并运行,但当下游邮件节点尝试附加文件时,文件已不存在。
$binary有两种方法可以保留二进制数据:
- 转换节点的传递选项。编辑字段节点有选项;Code节点可显式返回
includeOtherFields。若该选项可用,这是最简单的修复方法。binary: $input.item.binary - 分支输出并按位置合并。将源节点同时路由到转换分支和旁路分支,然后使用Merge节点的模式重新组合。JSON数据来自转换分支,二进制数据通过旁路分支保留。
combineByPosition
[Source with binary] ─┬─→ [Edit Fields: change JSON] ─┐
│ (binary stripped here) ├─→ [Merge: combineByPosition] ─→ [Email: attach]
└──────────────────────────────────┘
(bypass — binary passes through untouched)combineByPositionMERGE_FOR_CONTEXT.mdThe agent-tool binary boundary
Agent工具的二进制边界
This is the sharpest edge. An AI Agent talks to its tools (Custom Code Tool, Call n8n Workflow Tool, HTTP Request Tool, MCP tools) over JSON. Binary does not fit through that pipe in either direction. The fix is the same shape both ways: stage the bytes in storage, pass a key/URL through JSON, fetch on the other side.
Inbound — a user uploads a file the agent's tool must operate on:
- The chat trigger gives you a array. Split it out and upload each file to private storage under a hashed key.
files[] - Re-merge that branch before the agent runs (it's a synchronization barrier, not decoration), and set on the agent so N files don't trigger N agent runs.
executeOnce: true - Inject the keys into the agent's system prompt, listing both the original name (human context) and the storage key (what the tool needs), with an explicit "use EXACTLY this key".
- The tool receives the key as a string argument and downloads the file from storage itself.
Outbound — a tool generates a file the agent must return:
- The tool sub-workflow generates the binary, uploads it to storage, and returns JSON like .
{ "ok": true, "key": "...", "url": "https://...", "mimeType": "image/png" } - The agent embeds the URL in its reply (or passes the key to another tool).
passthroughBinaryImages: trueAGENT_TOOL_BINARY.mdBuilding the tool itself? See n8n-code-tool for the Custom Code Tool contract and n8n-workflow-patterns for the AI-Agent-with-tools shape.
这是最严格的限制。AI Agent通过JSON与工具(自定义代码工具、调用n8n工作流工具、HTTP请求工具、MCP工具)通信。二进制数据无法通过这条管道传递,无论方向如何。解决方法都是相同的:将字节数据预存到存储服务中,通过JSON传递密钥/URL,在另一端获取数据。
Inbound — a user uploads a file the agent's tool must operate on:
- 聊天触发器会返回数组。拆分该数组,并将每个文件上传到私有存储服务,使用哈希密钥命名。
files[] - 在Agent运行前重新合并该分支(这是同步屏障,而非装饰),并在Agent节点设置,避免N个文件触发N次Agent运行。
executeOnce: true - 将密钥注入Agent的系统提示词,同时列出原始文件名(供人类参考)和存储密钥(工具所需),并明确说明“必须使用此确切密钥”。
- 工具接收字符串形式的密钥,并自行从存储服务下载文件。
Outbound — a tool generates a file the agent must return:
- 工具子工作流生成二进制数据,上传到存储服务,并返回类似的JSON。
{ "ok": true, "key": "...", "url": "https://...", "mimeType": "image/png" } - Agent将URL嵌入回复中(或传递密钥给另一个工具)。
passthroughBinaryImages: trueAGENT_TOOL_BINARY.mdBuilding the tool itself? See n8n-code-tool for the Custom Code Tool contract and n8n-workflow-patterns for the AI-Agent-with-tools shape.
The CDN requirement for chat surfaces
聊天界面的CDN要求
When a workflow generates an image and the user wants it shown inside a chat message:
- Binary on the item isn't enough. The chat client renders messages that reference images by URL (or pushes bytes through the platform's own file-upload API). It never reads .
$binary - The bytes have to live somewhere a URL can fetch over HTTPS. Upload to an object store or drive first, then embed the returned URL.
- n8n has no built-in CDN. The user provides the storage.
Ask which storage they already use rather than defaulting to S3 — object storage (S3, R2, GCS, Azure Blob, Backblaze B2, Supabase Storage) and drive-style services (Dropbox, Google Drive, OneDrive, Box) all work and all change the URL shape. Cloudflare R2 is the lowest-friction starting point if they have nothing. For sensitive content, use a signed URL with an expiry rather than a permanently public one. See .
CDN_REQUIREMENT.md当工作流生成图片并需要在聊天消息中显示时:
- Binary on the item isn't enough. 聊天客户端通过URL引用图片来渲染消息(或通过平台自身的文件上传API传递字节数据)。它永远不会读取。
$binary - The bytes have to live somewhere a URL can fetch over HTTPS. 先上传到对象存储或云盘,再嵌入返回的URL。
- n8n has no built-in CDN. 存储服务由用户提供。
Ask which storage they already use rather than defaulting to S3 — object storage (S3, R2, GCS, Azure Blob, Backblaze B2, Supabase Storage) and drive-style services (Dropbox, Google Drive, OneDrive, Box) all work and all change the URL shape. Cloudflare R2 is the lowest-friction starting point if they have nothing. For sensitive content, use a signed URL with an expiry rather than a permanently public one. See .
CDN_REQUIREMENT.mdWhat's NOT available
不可用功能
- cannot carry binary. It fills tool parameters with strings, numbers, booleans, and objects — never file bytes. Pass a storage key instead.
$fromAI() - Tool arguments and returns are JSON only. There is no "binary parameter" on an agent tool, in or out.
- n8n ships no CDN or public file host. Serving a file over a URL is always something the user's storage does, not n8n.
- is a Code-node helper. It isn't available in the Custom Code Tool sandbox (see n8n-code-tool).
getBinaryDataBuffer
- cannot carry binary. 它仅用字符串、数字、布尔值和对象填充工具参数——绝不会包含文件字节。请传递存储密钥替代。
$fromAI() - Tool arguments and returns are JSON only. Agent工具没有“二进制参数”,无论输入还是输出。
- n8n ships no CDN or public file host. 通过URL提供文件始终由用户的存储服务完成,而非n8n。
- is a Code-node helper. 它在自定义代码工具沙箱中不可用(请参阅n8n-code-tool)。
getBinaryDataBuffer
Where Data Tables live
数据表的位置
For persistent tabular storage — reference-counting staged files, tracking which keys are live, dedup — that's the surface, owned by n8n-mcp-tools-expert. This skill does not cover Data Tables.
n8n_manage_datatable对于持久化表格存储——引用计数预存文件、跟踪有效密钥、去重——属于范畴,由n8n-mcp-tools-expert负责。本技能不涵盖数据表。
n8n_manage_datatableAnti-patterns
反模式
| Anti-pattern | What goes wrong | Fix |
|---|---|---|
Reading file contents from | Bytes live in | Read |
HTTP download without | Bytes arrive as mangled text in | Set |
Code node returns | The file is silently dropped downstream | Re-attach |
| JSON transform (Edit Fields/IF) eats the binary | Email/upload node finds nothing to attach | Pass-through option, or fan out + Merge by position |
Passing an uploaded file into a tool via | | Pre-stage to storage, inject the key in the system prompt, tool fetches by key |
Assuming | It only affects what the LLM sees, and only for images | Still need the upload-and-pass-key pattern for tools |
| Tool returns raw binary to the agent | Tool output is JSON; bytes don't survive (and bloat context) | Upload, return |
Posting | Chat clients render by URL, not raw bytes | Upload to storage/CDN, embed the URL or use the platform file API |
| Hardcoding base64 in a Code node | Huge workflow JSON, slow, leaky | Reference via |
| 反模式 | 问题所在 | 修复方案 |
|---|---|---|
从 | 字节数据存储在 | 读取 |
HTTP下载未设置 | 字节数据以乱码文本形式出现在 | 在HTTP请求节点设置 |
Code节点返回 | 文件在下游被静默丢失 | 在返回时重新附加 |
| JSON转换(编辑字段/IF)移除二进制数据 | 邮件/上传节点找不到可附加的文件 | 使用传递选项,或分支输出 + 按位置合并 |
通过 | | 预存到存储服务,在系统提示词中注入密钥,工具通过密钥获取文件 |
认为 | 它仅影响LLM的视觉输入,且仅适用于图片 | 工具仍需使用上传并传递密钥的模式 |
| 工具向Agent返回原始二进制数据 | 工具输出为JSON;字节数据无法保留(且会膨胀上下文) | 上传到存储服务,返回 |
将 | 聊天客户端通过URL渲染,而非原始字节数据 | 上传到存储/CDN,嵌入URL或使用平台文件API |
| 在Code节点中硬编码base64 | 工作流JSON体积庞大、运行缓慢、易泄露 | 通过 |
Reference files
参考文件
| File | Read when |
|---|---|
| First time handling binary, or reading/writing the |
| An agent tool needs an uploaded file, or produces one — the boundary in either direction |
| Binary disappears after a JSON transform and you need to re-attach it |
| Showing images in a chat surface or anywhere that needs URL-referenced images |
| 文件 | 阅读场景 |
|---|---|
| 首次处理二进制数据,或读写 |
| Agent工具需要处理上传文件或生成文件——双向边界场景 |
| JSON转换后二进制数据丢失,需要重新附加 |
| 在聊天界面或其他需要URL引用图片的场景显示图片 |
Integration with Other Skills
与其他技能的集成
n8n-code-javascript / n8n-code-python: the Code node is where you read/write raw bytes (, ). Those skills own the sandbox, helpers, and execution-mode detail — this skill owns the rule that binary must be re-attached on return.
getBinaryDataBufferBuffer.from(...).toString('base64')n8n-code-tool: the Custom Code Tool sandbox is narrower — no , no , no . When a tool needs a file, this skill's storage-key pattern is how it gets one.
$binarygetBinaryDataBuffer$fromAIn8n-workflow-patterns: the agent-tool binary boundary sits inside the AI-Agent-with-tools pattern; the CDN flow is a generate → upload → reply chain.
n8n-node-configuration: , , , are all conditional fields — use to confirm the exact names on the user's version.
responseFormatbinaryPropertyNameincludeOtherFieldsbinaryPropertyOutputget_noden8n-expression-syntax: addressing vs (webhook uploads in particular) is expression territory.
$binary.<key>.fileName$json.bodyn8n-validation-expert: a dropped binary slot is a silent failure — won't flag it. Confirm presence by inspecting the execution.
validate_workflown8n-mcp-tools-expert: owns (Data Tables) and — use the latter to confirm a slot actually survived a given node.
n8n_manage_datatablen8n_executionsbinaryn8n-error-handling: storage uploads and downloads fail; the inbound/outbound staging steps need error branches so a missing key doesn't 404 silently.
using-n8n-mcp-skills: the index of how these skills fit together.
n8n-code-javascript / n8n-code-python:Code节点是读取/写入原始字节数据的位置(、)。这些技能负责沙箱、辅助函数和执行模式的细节——本技能负责二进制数据必须在返回时重新附加的规则。
getBinaryDataBufferBuffer.from(...).toString('base64')n8n-code-tool:自定义代码工具沙箱的范围更窄——无、无、无。当工具需要文件时,本技能的存储密钥模式是解决方案。
$binarygetBinaryDataBuffer$fromAIn8n-workflow-patterns:Agent工具的二进制边界属于带工具的AI Agent模式;CDN流程是生成→上传→回复的链条。
n8n-node-configuration:、、、均为条件字段——使用确认用户版本的准确名称。
responseFormatbinaryPropertyNameincludeOtherFieldsbinaryPropertyOutputget_noden8n-expression-syntax:引用与(尤其是webhook上传)属于表达式范畴。
$binary.<key>.fileName$json.bodyn8n-validation-expert:二进制存储区被移除是静默故障——不会标记它。需通过检查执行记录确认其存在。
validate_workflown8n-mcp-tools-expert:负责(数据表)和——使用后者确认存储区是否在特定节点后保留。
n8n_manage_datatablen8n_executionsbinaryn8n-error-handling:存储服务的上传和下载可能失败;入站/出站预存步骤需要错误分支,避免密钥缺失导致静默404错误。
using-n8n-mcp-skills:这些技能如何协同工作的索引。
Verifying binary survived
验证二进制数据是否保留
Validation won't catch a stripped binary slot — it's a silent failure. Confirm it ran correctly:
- (or trigger a real run) to produce an execution.
n8n_test_workflow - to pull that execution, and inspect per-node output for the
n8n_executionsslot — it shows presence and metadata even if the base64 is too large to render.binary - The node where last appears is the node before the strip. That's where the pass-through or Merge goes.
binary
验证不会捕获二进制存储区被移除的情况——这是静默故障。请按以下步骤确认运行正确:
- 使用(或触发真实运行)生成执行记录。
n8n_test_workflow - 使用获取该执行记录,检查每个节点的输出是否包含
n8n_executions存储区——即使base64数据过大无法显示,也会显示其存在和元数据。binary - 最后出现的节点是移除前的节点。此处需要添加传递选项或Merge节点。
binary
Quick Reference Checklist
快速参考清单
- File contents read from — never
$binary.<key>$json - HTTP downloads use
responseFormat: "file" - Code nodes re-attach on return when the file must continue
binary - JSON transforms either pass binary through or Merge it back ()
combineByPosition - No attempt to pass binary into/out of an agent tool — keys/URLs through JSON instead
- used only for LLM vision, not as a tool channel
passthroughBinaryImages - Chat-surface images uploaded to storage; the URL is embedded, not the bytes
- Storage backend chosen with the user (not defaulted to S3); signed URLs for sensitive content
- Binary presence confirmed by inspecting the execution, not by validation
Remember: two slots, side by side. Data rides in , files ride in — and the moment a file has to cross an agent tool or reach a chat surface, it travels as a URL, not as bytes.
$json$binary- 文件内容从读取——绝不从
$binary.<key>读取$json - HTTP下载使用
responseFormat: "file" - 当文件需要继续传递时,Code节点在返回时重新附加
binary - JSON转换要么传递二进制数据,要么通过合并回来
combineByPosition - 不尝试将二进制数据传入/传出Agent工具——通过JSON传递密钥/URL替代
- 仅用于LLM视觉输入,而非工具通道
passthroughBinaryImages - 聊天界面图片上传到存储服务;嵌入URL而非字节数据
- 根据用户情况选择存储后端(不默认S3);敏感内容使用签名URL
- 通过检查执行记录确认二进制数据存在,而非仅依赖验证
记住:两个存储区并行存在。结构化数据在中,文件在中——当文件需要跨越Agent工具或到达聊天界面时,它以URL形式传递,而非字节数据。
$json$binary