Output Adapters
Adapters receive events one at a time during generation and route them to their destination. Synode ships 7 built-in adapters.
Adapter Summary
| Adapter | Use Case | Constructor |
|---|---|---|
ConsoleAdapter | Debugging, quick inspection | new ConsoleAdapter() |
InMemoryAdapter | Testing, assertions, dry runs | new InMemoryAdapter() |
FileAdapter | Local file output (JSONL, JSON, CSV) | new FileAdapter({ path, format }) |
HttpAdapter | Webhook/API ingestion with batching | new HttpAdapter({ url, batchSize }) |
CallbackAdapter | Custom per-event logic | new CallbackAdapter(fn) |
CompositeAdapter | Fan-out to multiple adapters | new CompositeAdapter([...adapters]) |
StreamAdapter | Node.js Writable streams | new StreamAdapter(stream) |
ConsoleAdapter
Prints each event as pretty-printed JSON to stdout. Default adapter when none is specified.
import { generate, ConsoleAdapter } from '@synode/core';
await generate(journey, {
users: 10,
adapter: new ConsoleAdapter(),
});InMemoryAdapter
Stores events in an array. Access via adapter.events. Call adapter.clear() to reset.
import { generate, InMemoryAdapter } from '@synode/core';
const adapter = new InMemoryAdapter();
await generate(journey, { users: 50, adapter });
console.log(adapter.events.length); // total event count
console.log(adapter.events[0].name); // first event name
adapter.clear(); // reset for next runFileAdapter
Writes events to disk. Supports three formats and optional daily partitioning.
import { generate } from '@synode/core';
import { FileAdapter } from '@synode/adapter-file';
// JSONL: one JSON object per line, appended per event
const jsonl = new FileAdapter({ path: './out/events.jsonl', format: 'jsonl' });
// JSON: buffered array, written on close
const json = new FileAdapter({ path: './out/events.json', format: 'json' });
// CSV: header + rows, appended per event
const csv = new FileAdapter({ path: './out/events.csv', format: 'csv' });
await generate(journey, { users: 1000, adapter: jsonl });Daily Partitioning
Split output into date-based files using the event timestamp.
const adapter = new FileAdapter({
path: './out', // base directory for partitioned files
format: 'csv',
partition: 'daily',
filePattern: 'events-{date}.{ext}', // default pattern
});
// Creates: ./out/events-2026-01-15.csv, ./out/events-2026-01-16.csv, etc.Options: path (required), format ('jsonl'|'json'|'csv', required), partition ('daily'|'none', default 'none'), filePattern (template with {date} and {ext}, default 'events-{date}.{ext}').
HttpAdapter
Sends events to an HTTP endpoint with batching, flush intervals, and retry with exponential backoff.
import { generate } from '@synode/core';
import { HttpAdapter } from '@synode/adapter-http';
const adapter = new HttpAdapter({
url: 'https://api.example.com/ingest',
batchSize: 50,
flushInterval: 3000,
maxRetries: 3,
headers: { Authorization: 'Bearer token-123' },
});
await generate(journey, { users: 5000, adapter });
await adapter.close(); // flush remaining bufferOptions: method ('POST'|'PUT', default 'POST'), headers, batchSize (default 1), flushInterval (ms, default 5000), maxRetries (default 3), transform (custom body shape function). Retries with exponential backoff on 5xx/429.
CallbackAdapter
Invokes a function for each event. Supports sync and async callbacks.
import { generate, CallbackAdapter } from '@synode/core';
const adapter = new CallbackAdapter(async (event) => {
await db.insert('events', { name: event.name, userId: event.userId, payload: event.payload });
});
await generate(journey, { users: 100, adapter });CompositeAdapter
Fans out each event to multiple child adapters in parallel. Calls close() on all children.
import { generate, ConsoleAdapter } from '@synode/core';
import { FileAdapter } from '@synode/adapter-file';
import { HttpAdapter } from '@synode/adapter-http';
import { CompositeAdapter } from '@synode/adapter-composite';
const adapter = new CompositeAdapter([
new ConsoleAdapter(),
new FileAdapter({ path: './out/events.jsonl', format: 'jsonl' }),
new HttpAdapter({ url: 'https://api.example.com/ingest', batchSize: 50 }),
]);
await generate(journey, { users: 1000, adapter });
await adapter.close(); // closes all childrenStreamAdapter
Writes events to any Node.js Writable stream. Default format jsonl streams per event; json buffers and writes on close.
import { createWriteStream } from 'node:fs';
import { generate } from '@synode/core';
import { StreamAdapter } from '@synode/adapter-stream';
const stream = createWriteStream('./events.jsonl');
const adapter = new StreamAdapter(stream);
await generate(journey, { users: 500, adapter });
await adapter.close();close() Lifecycle
Adapters with buffered state (FileAdapter JSON mode, HttpAdapter, StreamAdapter) require close() to flush. generate calls close() automatically after all users are processed. If using an adapter outside generate, call close() manually.
