Load Testing without the
Runtime Overhead.

Script in JavaScript. Execute in Rust.
The world's most efficient load testing engine. 180K RPS with sub-millisecond latency on just 200 workers.

$ cargo install fusillade
$ fusi run scenario.js -w 200
[INFO] Spawning 200 workers...
[DONE] 180,642 RPS | P50: 0.05ms | P95: 0.13ms | 100% success

Raw Performance

Benchmarked with 200 concurrent workers

180K
Requests/sec
0.13ms
P95 Latency
69MB
Memory Usage
100%
Success Rate

Benchmarked on localhost against a Rust/Axum server with 200 workers for 30 seconds. Real-world results will vary based on network latency and server complexity.

Why Rust?

Traditional load testing tools are built on garbage-collected runtimes. At high concurrency, GC pauses introduce latency spikes that pollute your metrics. Fusillade eliminates this with zero-allocation hot paths and predictable memory usage.

Green-Thread Workers

Each worker runs as a lightweight green-thread coroutine with its own QuickJS runtime. 50,000 workers share just 16 OS threads with zero-cost context switching. Raw TCP connections with per-worker keep-alive deliver sub-millisecond latency at any scale.

Memory Efficiency

10,000 concurrent workers in ~318MB of RAM. Rust's ownership model eliminates memory leaks and fragmentation. No GC pauses and no garbage collector means consistent sub-millisecond latencies even under extreme load.

Accurate Metrics

Latency measurements exclude JavaScript execution overhead—only network time and body reads are counted. HDR histograms capture precise percentiles without bucket quantization errors.

Write Tests in JavaScript

Familiar syntax. Full ES Module support. Powerful built-ins.

Load Test with Stages

export const options = {
  stages: [
    { duration: '30s', target: 100 },  // Ramp to 100 workers
    { duration: '1m', target: 100 },   // Hold at peak
    { duration: '10s', target: 0 },    // Ramp down
  ],
  thresholds: {
    'http_req_duration': ['p95 < 500'],
    'http_req_failed': ['rate < 0.01'],
  }
};

export default function () {
  const res = http.post('https://api.example.com/checkout',
    JSON.stringify({ item_id: '12345' }),
    { headers: { 'Content-Type': 'application/json' } }
  );

  check(res, {
    'status is 200': (r) => r.status === 200,
    'response time OK': (r) => r.timings.duration < 500,
  });

  sleep(1);
}

Lifecycle Hooks

// Load test data once, share across all workers
const users = new SharedArray('users', () =>
  JSON.parse(open('./data/users.json'))
);

export function setup() {
  // Runs once before test starts
  const loginRes = http.post('/api/login', {
    username: 'admin', password: 'secret'
  });
  return { token: JSON.parse(loginRes.body).token };
}

export default function(data) {
  // Each worker receives setup data
  const user = users[__WORKER_ID % users.length];

  http.get('/api/profile', {
    headers: { 'Authorization': `Bearer ${data.token}` }
  });
}

export function teardown(data) {
  // Cleanup after all workers finish
  http.post('/api/logout');
}

Multi-Protocol Support

Test any backend with native protocol implementations

HTTP/1.1 & HTTP/2

const res = http.post(url, body, {
  headers: { 'Content-Type': 'application/json' },
  timeout: '10s',
  name: 'CreateOrder'
});
// res.proto → "h1" or "h2"

WebSockets

const socket = ws.connect('wss://api.example.com');
socket.send(JSON.stringify({ type: 'subscribe' }));
const msg = socket.recv();
socket.close();

gRPC

const client = new GrpcClient();
client.load(['./hello.proto'], ['./protos']);
client.connect('http://localhost:50051');
const res = client.invoke('helloworld.Greeter/SayHello', { name: 'World' });

MQTT

const mqtt = new JsMqttClient();
mqtt.connect('localhost', 1883, 'client-1');
mqtt.publish('sensors/temp', '22.5');
mqtt.close();

AMQP (RabbitMQ)

const amqp = new JsAmqpClient();
amqp.connect('amqp://localhost');
amqp.publish('', 'my-queue', JSON.stringify({ event: 'order.created' }));

Server-Sent Events

const client = sse.connect('/events');
const event = client.recv();
// { event: 'update', data: '...', id: '1' }
client.close();

Browser Automation (Chromium)

const browser = chromium.launch();
const page = browser.newPage();
page.goto('https://example.com/login');
page.type('#username', 'testuser');
page.type('#password', 'secret');
page.click('#submit');

const perf = page.metrics();
print(`DOM interactive: ${perf.domInteractive - perf.navigationStart}ms`);

const screenshot = page.screenshot();  // Auto-captured on check() failures
browser.close();

Flexible Execution

Multiple execution models for different testing scenarios

Load Profiles

  • Ramping Workers — Gradually scale workers up/down with stages
  • Constant Arrival Rate — Fixed RPS regardless of response time
  • Per-Worker Iterations — Each worker runs N iterations then exits
  • Multiple Scenarios — Run different user behaviors concurrently

Multi-Scenario Example

export const options = {
  scenarios: {
    browse: {
      workers: 50,
      duration: '2m',
      exec: 'browseProducts',
    },
    checkout: {
      workers: 10,
      duration: '90s',
      exec: 'checkoutFlow',
      startTime: '30s',  // Delayed start
    },
  },
};

export function browseProducts() { ... }
export function checkoutFlow() { ... }

Distributed Load Generation

Scale horizontally across multiple machines or Kubernetes pods

Architecture

+-------------------------------------+
|         Controller (:9000)          |
|   Dashboard / Orchestration / DB    |
+-----------------+-------------------+
                  | gRPC
     +------------+------------+
     |            |            |
     v            v            v
+--------+   +--------+   +--------+
| Worker |   | Worker |   | Worker |
|  :8080 |   |  :8080 |   |  :8080 |
+--------+   +--------+   +--------+

Quick Start

# Start workers
fusillade worker --connect controller:9001

# Or run the controller
fusillade controller --listen 0.0.0.0:9000

# Dispatch via API
curl -X POST http://controller:9000/api/dispatch \
  -d '{"script_content": "...", "config": {...}}'

Kubernetes Native

  • • HorizontalPodAutoscaler scales workers 3 → 50 pods
  • • Automatic asset distribution (scripts + data files)
  • • Real-time dashboard at /dashboard
  • • SQLite history for performance trend analysis

Chaos Engineering Built-In

Test system resilience with native fault injection

Jitter Injection

Add artificial latency to simulate slow networks or upstream services

fusi run test.js --jitter 500ms

Request Dropping

Randomly fail requests to simulate packet loss or connection resets

fusi run test.js --drop 0.05

Config-Based

Define chaos parameters in your script options

export const options = {
  jitter: '250ms',
  drop: 0.03,
};

Developer Experience

Tools that fit into your existing workflow

HAR Recording

Record browser sessions and convert to test scripts

fusi record -o flow.js
fusi convert --input recording.har

TypeScript Support

Generate type definitions for IDE autocomplete

fusi types -o index.d.ts

CI/CD Integration

Export to JUnit XML, CSV, JSON, or OTLP

fusi run test.js --headless \
  --out junit=results.xml \
  --out csv=metrics.csv

Cost Estimation

Estimate bandwidth costs before running large tests

fusi run heavy.js --estimate-cost
# Est. AWS Cost: ~$0.22 (2.45 GB)

Smart Error Replay

Debug failed requests after a test run

# Export failures to cURL commands
fusi export fusillade-errors.json --format curl

# Replay failed requests
fusi replay fusillade-errors.json --parallel

Interactive Control

Control running tests in real-time

fusi run test.js --interactive
> ramp 100    # Scale to 100 workers
> pause       # Pause execution
> resume      # Resume
> status      # Show current stats

Batteries Included

Built-in utilities for common load testing needs

crypto

crypto.md5(data)
crypto.sha1(data)
crypto.sha256(data)
crypto.hmac('sha256', key, data)

encoding

encoding.b64encode('user:pass')
encoding.b64decode(token)

utils

utils.uuid()
utils.randomInt(1, 100)
utils.randomString(16)
utils.randomItem(users)

Custom Metrics

Track business-level metrics with thresholds

// Define thresholds in options
export const options = {
  thresholds: {
    'checkout_duration': ['p95 < 500'],
    'payment_success': ['rate > 0.99'],
  }
};

// Record custom metrics
metrics.histogramAdd('checkout_duration', Date.now() - start);
metrics.counterAdd('items_sold', 3);
metrics.rateAdd('payment_success', true);
metrics.gaugeSet('queue_depth', 42);

// Query stats programmatically
const s = stats.get('CreateOrder');
if (s.p95 > 500) print('Warning: P95 latency degrading');

Get Started in Seconds

$ cargo install fusillade
$ fusi types -o index.d.ts # IDE autocomplete
$ fusi run scenario.js -w 1000 -d 30s

~35MB binary. No runtime needed. Works on Linux, macOS, and Windows.