npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

n8nlint

v0.3.0

Published

Static analysis for n8n workflows — catch runtime bugs before production

Readme

n8nlint

Static analysis for n8n workflows — like ESLint for your automation pipelines.

n8n workflows can contain subtle bugs that only surface at runtime with specific data constellations: race conditions, dead branches, missing loop-backs, unhandled errors. n8nlint analyzes workflow JSON files and catches these patterns before they cause issues in production.

Installation

npm install -g n8nlint

Or use directly with npx:

npx n8nlint ./workflows/*.json

Usage

# Lint a single workflow
n8nlint workflow.json

# Lint all workflows in a directory
n8nlint ./workflows/*.json

# JSON output for CI/CD
n8nlint --format json ./workflows/*.json

# Check exit code
n8nlint workflow.json && echo "PASS" || echo "FAIL"

Exit Codes

| Code | Meaning | |------|---------| | 0 | No errors (warnings/infos don't affect exit code) | | 1 | One or more errors found |

Rules

no-merge-in-loop (error)

Detects Merge nodes inside splitInBatches loops. This causes the loop to silently halt after the first iteration because the Merge node waits for all inputs but only receives data from one branch per iteration.

Fix: Remove the Merge node and connect both branches directly to the next node. n8n supports multiple input connections on a single node input.

no-dead-end-in-subworkflow (warning / info)

Detects multi-output nodes with unconnected outputs in sub-workflows. n8n returns data from the last executed node in a sub-workflow. Dead-end outputs can finish after the intended output node due to async execution, causing the parent workflow to receive wrong data.

| Pattern | Severity | |---------|----------| | compareDatasets with dead-end outputs | warning | | IF / Switch with dead-end outputs | info |

Fix: Replace multi-output nodes with a single-output Code node that returns only the desired items.

no-dual-branch-convergence (error)

Detects nodes with onError: continueErrorOutput where both the success and error branches converge on the same downstream node. When items split between branches, the downstream node fires twice — first with partial success data, then with partial error data.

Fix: Change onError from continueErrorOutput to continueRegularOutput. All items flow through one branch and downstream nodes fire only once.

no-unreachable-nodes (warning)

Detects nodes without incoming connections (excluding trigger nodes). Unreachable nodes will never execute and are likely leftover from workflow edits.

Fix: Connect the node to the workflow or remove it if unused.

splitInBatches-missing-loop-back (error)

Detects splitInBatches loops where the loop body has no path back to the split node. Without this connection, only the first batch is processed and the rest of the data is silently dropped.

Fix: Connect the last node in the loop body back to the splitInBatches node to complete the loop.

http-no-error-handling (info)

Detects HTTP Request nodes without an onError configuration. Without error handling, any HTTP error (timeout, 4xx, 5xx) will stop the entire workflow execution.

Fix: Set onError to continueRegularOutput or continueErrorOutput to handle HTTP errors gracefully.

code-node-no-require (error)

Detects require() calls in Code node jsCode. Since n8n v2.10+, the sandbox blocks require() for Node.js built-in modules — the error only surfaces at runtime.

Fix: Use built-in n8n nodes or helpers instead of require().

code-node-no-env (error)

Detects $env access in Code node jsCode. The n8n sandbox blocks $env, causing a cryptic runtime error.

Fix: Use a Set node or config node to pass environment variables into the workflow.

code-node-no-credential-helpers (error)

Detects credential/HTTP helper APIs (this.getCredentials(), this.helpers.httpRequestWithAuthentication(), this.helpers.requestOAuth2(), this.helpers.request()) in Code nodes. These APIs are only available in custom nodes.

Fix: Use an HTTP Request node for authenticated API calls.

api-clean-json (warning)

Detects top-level workflow JSON properties (active, triggerCount, staticData, pinData, versionId) that are not accepted by the n8n REST API and should be stripped before version control or API import.

Fix: Remove the flagged properties from the workflow JSON.

large-inline-code (info)

Detects Code nodes with more than 100 lines of inline JavaScript. Large inline code blocks reduce maintainability.

Fix: Extract the code logic into a separate sub-workflow.

merge-mode-ambiguity (info)

Detects Merge nodes without an explicitly configured mode parameter. The default behavior may not match the developer's intention.

Fix: Set the mode parameter explicitly (e.g., append, combine, chooseBranch).

prefer-named-node-reference (warning)

Detects fragile $json references in nodes with multiple inputs. When workflows are restructured, $json silently references a different predecessor node. Skips Code nodes and nodes with only one input.

Fix: Replace $json with $('NodeName').first().json to make the data source explicit.

binary-needs-decode-before-upload (warning)

Detects upload nodes (Google Drive, S3, FTP) receiving binary data from HTTP Request nodes without a Code node for binary decoding. In n8n's filesystem-v2 mode, this results in corrupted uploads (Base64-encoded content, 33% larger files).

Fix: Add a Code node between the HTTP Request and upload node to call getBinaryDataBuffer() and prepareBinaryData().

Configuration

Create a .n8nlintrc.yml in your project root:

rules:
  no-merge-in-loop: error
  no-dead-end-in-subworkflow: warning
  no-dual-branch-convergence: error
  no-unreachable-nodes: warning
  splitInBatches-missing-loop-back: error
  http-no-error-handling: info
  code-node-no-require: error
  code-node-no-env: error
  code-node-no-credential-helpers: error
  api-clean-json: warning
  large-inline-code: info
  merge-mode-ambiguity: info
  prefer-named-node-reference: warning
  binary-needs-decode-before-upload: warning

Valid values: error, warning, info, off

Inline Ignores

Add n8nlint-ignore to a node's name to skip it:

HTTP Request n8nlint-ignore

GitHub Action

- uses: jnikolov/[email protected]
  with:
    patterns: './workflows/*.json'

Programmatic API

import { parseWorkflow, runRules, DEFAULT_CONFIG } from 'n8nlint';
import { readFileSync } from 'fs';

const workflow = JSON.parse(readFileSync('workflow.json', 'utf-8'));
const graph = parseWorkflow(workflow);
const violations = runRules(graph, workflow, DEFAULT_CONFIG);

for (const v of violations) {
  console.log(`[${v.severity}] ${v.message}`);
}

Roadmap

  • v0.4 — Auto-layout and formatting (Prettier for n8n)
  • v0.5 — Expression analysis rules (invalid references, type mismatches)
  • v0.6 — n8n API integration (lint workflows directly from n8n instances)

Disclaimer

n8nlint is an independent open-source project. It is not affiliated with, endorsed by, or sponsored by n8n GmbH.

License

MIT