data/skills/n8n-binary-and-data/README.md
Expert guidance for handling files and binary data in n8n — the $binary vs $json split, reading and writing bytes, keeping binary alive across transforms, the AI-agent tool boundary, and the CDN/URL requirement for chat surfaces.
$binary, not $jsonEvery n8n item has two independent slots that flow side by side:
$json | $binary | |
|---|---|---|
| Holds | Structured data (numbers, strings, objects) | File bytes (base64) plus metadata |
| Shape | { customerId: 42 } | { data, mimeType, fileName, fileExtension } |
| Read in Code | $json.field | this.helpers.getBinaryDataBuffer(i, 'data') |
| Crosses an agent tool | Yes (JSON args/returns) | No — pass a key/URL instead |
| Renders in a chat surface | n/a | No — needs a URL, not raw bytes |
Reading $json.data for a downloaded PDF gives you nothing — the bytes are in $binary.data. This skill teaches the actual contract for files.
$json for data, $binary for files; they never mixgetBinaryDataBuffer, write by building the slot (base64 + mimeType + fileName)$json and getting empty dataresponseFormat: "file" → mangled text instead of bytesActivates when you:
$binary, binaryPropertyName, base64, or "read the PDF"Example queries:
$json.data is empty — where's the file?"Main skill content — loaded when the skill activates.
$binary; agent tools are JSON-only; chat needs a URL)binaryPropertyNameresponseFormat: "file", Read Files, downloads)The $binary slot in depth.
getBinaryDataBuffer read and base64 write recipesThe JSON-only boundary between an AI Agent and its tools.
executeOnce: true{ key, url }passthroughBinaryImages (vision only, image only)Re-attaching binary after a JSON transform strips it.
combineByPositionWhy chat surfaces need a served URL.
$binary doesn't render; how chat clients embed imagesconst buffer = await this.helpers.getBinaryDataBuffer(0, 'data');
const text = buffer.toString('utf-8');
return [{
json: { ok: true },
binary: {
report: {
data: Buffer.from(text).toString('base64'),
mimeType: 'text/plain',
fileName: 'report.txt',
},
},
}];
[Source] ─┬─→ [Edit Fields] ─┐
└──────────────────┴─→ [Merge: combineByPosition]
{ key, url } in JSONn8n-code-javascript / n8n-code-python: own the Code-node sandbox and helpers; this skill owns the rule that binary must be re-attached on return.
n8n-code-tool: the Custom Code Tool sandbox has no $binary/getBinaryDataBuffer — a tool gets files via the storage-key pattern.
n8n-workflow-patterns: the agent-tool boundary and the generate → upload → reply flow live inside larger patterns.
n8n-node-configuration: responseFormat, binaryPropertyName, includeOtherFields, binaryPropertyOutput are conditional fields — confirm names with get_node.
n8n-expression-syntax: addressing $binary.<key> and webhook uploads under $json.body.
n8n-validation-expert: a stripped binary slot is a silent failure validation won't flag.
n8n-mcp-tools-expert: owns n8n_manage_datatable (Data Tables) and n8n_executions (confirm binary survived).
n8n-error-handling: storage uploads/downloads fail — staging steps need error branches.
using-n8n-mcp-skills: the index of how these skills fit together.
| Need | Use |
|---|---|
| Where file bytes live, reading/writing binary | n8n-binary-and-data |
| Language-level Code-node logic (arrays, dates, HTTP) | n8n-code-javascript / n8n-code-python |
| A tool an AI agent invokes | n8n-code-tool |
| Persistent tabular storage (dedup, state) | n8n-mcp-tools-expert (n8n_manage_datatable) |
| Overall workflow shape | n8n-workflow-patterns |
After using this skill, you should be able to:
$binary, never $jsonresponseFormat: "file" on HTTP downloadsbinary on a Code node return so the file survivespassthroughBinaryImages is vision-only and doesn't feed toolsAuthoritative facts in this skill come from:
$binary slot, property names, storagegetBinaryDataBuffer and the helpers surfacecombineByPosition semanticspassthroughBinaryImagesVersion: 1.0.0
Compatibility: n8n with $binary items; agent-tool patterns require the LangChain AI Agent node.
Remember: two slots, side by side. Data rides in $json, files ride in $binary — and the moment a file crosses an agent tool or reaches a chat surface, it travels as a URL, not as bytes.