Back to N8n

Performance Benchmarks

packages/testing/performance/README.md

1.37.23.1 KB
Original Source

Performance Benchmarks

Microbenchmarks for measuring and tracking performance of critical code paths.

When to Use Benchmarks

Good fit:

  • Hot paths executed thousands of times (expression evaluation, data transforms)
  • Comparing implementation approaches (current vs proposed)
  • Detecting regressions in critical code

Not a good fit:

  • API endpoint latency (use load testing - k6, artillery)
  • Database query performance (use query analysis tools)
  • Frontend rendering (use browser profiling)
  • One-off operations (startup time, migrations)

Rule of thumb: If it runs millions of times per day across all users, benchmark it.

Commands

bash
pnpm --filter=@n8n/performance bench          # Run benchmarks
pnpm --filter=@n8n/performance bench:baseline  # Save baseline for local comparison
pnpm --filter=@n8n/performance bench:compare   # Compare against baseline (>10% = fail)

CI Regression Detection

Benchmarks run automatically on PRs that touch packages/testing/performance/** or packages/workflow/src/**. CodSpeed counts CPU instructions instead of wall-clock time, producing deterministic results regardless of runner load. It comments on PRs with results and regression warnings.

You can also trigger benchmarks manually for any branch via Actions > Test: Benchmarks > Run workflow.

Local vs CI

Local (bench)CI
MeasurementWall-clock time (Hz, ms)CPU instruction count
Noise15-30% varianceNear-zero variance
Best forQuick sanity checks, comparing approachesAutomated regression detection

Local benchmarks are useful for eyeballing performance during development. Use bench:baseline + bench:compare for before/after comparisons on the same machine in the same session.

Adding a Benchmark

typescript
// benchmarks/my-feature/thing.bench.ts
import { bench, describe } from 'vitest';

// Setup runs once, not measured
const data = createTestData();

describe('My Feature', () => {
  bench('operation name', () => {
    doTheThing(data);
  });
});

Reading Results

name                hz      min    max   mean    p99    rme   samples
my operation    20,000   0.04   0.20   0.05   0.10  ±0.5%   10000
ColumnMeaning
hzOperations per second (higher = faster)
meanAverage time per operation in ms
p9999th percentile - worst case latency
rmeMargin of error - lower = more reliable
samplesNumber of iterations run

Current Benchmarks

AreaWhat it measuresWhy it matters
Expression Engine={{ }} evaluation speedRuns for every node parameter

Notes

This package pins vitest@^3.2.0 independently from the monorepo catalog (^3.1.3) because CodSpeed requires vitest 3.2+.

Tips

  1. Keep benchmarks focused - one thing per bench, not workflows
  2. Use realistic data sizes - 100 items is typical, 10k is stress test
  3. Compare approaches - benchmark both before deciding
  4. Don't over-benchmark - only critical hot paths need this