Atlas / Skills / czlonkowski / n8n Binary and Data Skill

n8n Binary and Data SkillSAFE

skills/czlonkowski/n8n-binary-and-data

n8n skillset for Claude Code to build flawless n8n workflows

Verdict
SAFE
Grade
B
Trust score
89 /100
Version
—
Hosts
—
License
MIT
Stars
6,493
01

Overview

From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.

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.

⚠️ File contents live in $binary, not $json

Every n8n item has two independent slots that flow side by side:

Reading $json.data for a downloaded PDF gives you nothing — the bytes are in $binary.data. This skill teaches the actual contract for files.

What This Skill Teaches

Core Concepts

  1. Two slots per item — $json for data, $binary for files; they never mix
  2. Read bytes via `getBinaryDataBuffer`, write by building the slot (base64 + mimeType + fileName)
  3. Binary is silently stripped by JSON-only transforms — pass it through or Merge it back
  4. The agent-tool boundary is JSON only — pre-stage to storage, pass keys/URLs
  5. Chat surfaces render by URL — upload to storage/CDN first

Top issues this skill prevents

  1. Reading file contents from $json and getting empty data
  2. HTTP download without responseFormat: "file" → mangled text instead of bytes
  3. A Code node dropping the binary slot by not re-attaching it on return
  4. Binary disappearing after an Edit Fields / IF / Code transform
  5. An AI agent tool that receives nothing when handed an uploaded file
  6. A generated image that "doesn't display" in Slack/Discord/Teams

Skill Activation

Activates when you:

  • Work with files, images, PDFs
Read from source at commit 97457683608eOBSERVED · 2026-10-21
Advertisement
02

What it tells the agent

The instruction file, verbatim from the audited commit — this is the text the model reads, and the surface the audit's instruction layer examines. Quoted here so you can judge it without cloning anything.

---
name: n8n-binary-and-data
description: Handle files and binary data in n8n correctly. Use when working with files, images, PDFs, attachments, uploads or downloads, base64, vision/multimodal input, or when an AI agent needs a file as tool input or output — and whenever the user mentions $binary, binaryPropertyName, "read the PDF", "attach the file", "send the image", Merge losing binary, or a CDN for chat images. Covers the $binary vs $json split, reading/writing binary, keeping binary alive across transforms with Merge, the agent-tool binary boundary, and the CDN/URL requirement for chat surfaces.
---

# n8n Binary and Data

Every n8n item carries two independent slots: `$json` for structured data and `$binary` for file bytes. They travel side by side through the workflow. File contents — the actual PDF, image, or zip — live in `$binary`, never in `$json`. 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.

This 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.

---

## The three rules that prevent 90% of binary bugs

1. **File contents are in `$binary`, not `$json`.** After an HTTP download, a "Read Files", or an email-attachment trigger, the bytes sit in `$binary.<key>`. `$json` holds metadata at most. Reading `$json.data` for file contents gives you nothing.

2. **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`.

3. **Chat surfaces render images by URL, not by `$binary`.** 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 `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 `binary` (`invoice` here) is the **binary property name**. Most file-handling nodes have a `binaryPropertyName` parameter that points at it — the producer names the slot, the consumer references it by that name. The default key across most nodes is `data`, so when nothing tells you otherwise, assume `$binary.data`.

`$json` and `$binary` are separate namespaces. An expression like `{{ $binary.invoice.fileName }}` reads file metadata; `{{ $json.customerId }}` reads data. They never mix.

This split also explains a webhook gotcha: a Webhook trigger receiving `multipart/form-data` puts the uploaded file in `$binary` and the accompanying form fields in `$json.body` — so an uploaded file is not somewhere under `$json` at all. (The `$json.body` nesting for webhooks is **n8n-expression-syntax** territory.)

See `BINARY_BASICS.md` for the full slot anatomy, mime types, and size limits.

---

## Producing binary

You rarely build a `$binary` slot by hand — nodes populate it for you:

| Source | How binary appears |
|---|---|
| HTTP Request with `responseFormat: "file"` | Response body lands in `$binary.data` (or the name you set) |
| Read/Write Files from Disk | File contents read into `$binary` |
| Storage downloads (S3, Google Drive, Dropbox, etc.) | Downloaded file in `$binary.<key>` |
| Email triggers with attachments | Each attachment arrives in `$binary` |
| Provider AI media nodes (image/audio gen) | Set `options.binaryPropertyOutput` so the bytes land where the next node looks |

For an HTTP download, the one field that matters is `responseFormat`. Confirm it with `get_node` on `nodes-base.httpRequest` — leaving it as the default JSON/string format is the classic reason a downloaded file ends up as garbled text in `$json` instead of clean bytes in `$binary`.

---

## Reading and writing binary in a Code node

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 `getBinaryDataBuffer` — do not try to base64-decode `$binary.<key>.data` by hand:

```javascript
// 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 `[{ json: {...} }]` without re-attaching `binary` **silently drops the file**. See `BINARY_BASICS.md`.

---

## Keeping binary alive across transforms

JSON-only nodes — Edit Fields (Set), Code, IF, and others — can drop the `$binary` 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.

Two ways to keep it:

- **Pass-through option on the transforming node.** Edit Fields has `includeOtherFields`; a Code node can return `binary: $input.item.
03

Trust audit

SAFEgrade B · trust 89/100 Nothing in the source contradicts what it says it does. Grade A is reserved for packages that have also passed the behavioural sandbox.

LayerWhat it checksResult
L0Provenance & inventoryPASS
L1Static analysis of the codeNA
L2Instruction surface (what it tells the agent)PASS
L3Class-specific surfacePASS
L4Behavioural (sandbox)SKIPPED

What the source does

Filesystem
none-observed
Network
none-observed
Shell
none-observed
Dependencies
pinned
Secrets in source
none-found

Findings (0)

No findings outside the package's declared scope.

Gates applied: no_behavioural_pass.

Audited 2026-10-21 · audit v0.4.1 · source sha 97457683608efull audit observations/trust-audit/skill/czlonkowski__n8n-binary-and-data.json · Report an issue / request a re-scan
04

Audit history

Every audit this skill has had.

DateSourceVerdictGradeScoreChange
2026-10-2197457683608eSAFEB89first audit
05

Questions

What does the n8n-binary-and-data — czlonkowski/n8n-skills skill do?

n8n skillset for Claude Code to build flawless n8n workflows

Is n8n-binary-and-data — czlonkowski/n8n-skills safe to install?

The audit found nothing in the source that contradicts what it says it does, and graded it B (89/100). Grade A is held back for packages that have also passed a sandboxed behavioural run, which is why a clean skill reads B.

What can n8n-binary-and-data — czlonkowski/n8n-skills access on my machine?

The audit observed no filesystem, network or shell use at all in its source.

How current is this page?

The grade is for one exact copy of the source (97457683608e), read on 2026-10-21. The repository is watched, and a new audit runs when it changes — this is the first audit.

Add this badge to your README

Shows this page's audit result and links back to it. It updates when the audit does.

ModelsAtlas audit badge

Markdown
[![ModelsAtlas audit: n8n Binary and Data Skill](https://modelsatlas.com/skills/czlonkowski/n8n-binary-and-data/badge.svg)](https://modelsatlas.com/skills/czlonkowski/n8n-binary-and-data/)

Not your listing, or something out of date? Claim or update your listing.

Advertisement