This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
backendcritical PriorityID: bun-websocket-dynamic-backpressure-autopacing

Bun 1.2 WebSocket Dynamic Backpressure Auto-Pacing Standard

Enforces strict socket-level backpressure management during high-throughput WebSocket broadcast and fan-out operations in Bun 1.2+. Eliminates unconstrained heap memory growth and OOM crashes by monitoring `ws.getBufferedAmount()` and suspending publisher pipelines until the `drain` event clears the kernel network buffer.

Prohibited Anti-Pattern: Unchecked Fire-and-Forget Broadcast Loops Causing Heap Exhaustion Under Slow Clients

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Bun 1.2 WebSocket Dynamic Backpressure Auto-Pacing Standard - Enforces strict socket-level backpressure management during high-throughput WebSocket broadcast and fan-out operations in Bun 1.2+. Eliminates unconstrained heap memory growth and OOM crashes by monitoring `ws.getBufferedAmount()` and suspending publisher pipelines until the `drain` event clears the kernel network buffer.
globs: src/**/*.ts, server/**/*.ts, lib/**/*.ts
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/bun-websocket-dynamic-backpressure-autopacing"
---

# Bun 1.2 WebSocket Dynamic Backpressure Auto-Pacing Standard

> **Severity**: CRITICAL | **Category**: backend
> **Anti-Pattern Warning**: Unchecked Fire-and-Forget Broadcast Loops Causing Heap Exhaustion Under Slow Clients

## System Constraints
You are a Principal Backend Architect enforcing Bun 1.2 WebSocket backpressure guardrails. Mandate that all high-throughput WebSocket streaming and pub/sub message dispatching honor the native kernel buffer limits via `ws.getBufferedAmount()`, `ws.send()` return codes, and the `drain` handler. Prevent naive for-loops that enqueue outbound frames unbounded into v8/JSC heap memory when communicating with lagging or adversarial clients.

## Strict Guidelines
- Engineers MUST ALWAYS verify the numeric return value of `ws.send(data)` or inspect `ws.getBufferedAmount()` prior to enqueuing subsequent frames in publisher loops.
- Engineers MUST NOT rely on synchronous `for` or `forEach` loops over subscribers when dispatching high-frequency telemetry, market data, or fan-out payloads without per-socket buffer threshold checks.
- Services MUST implement the `drain(ws)` socket lifecycle hook in `Bun.serve({ websocket: { drain(ws) { ... } } })` to resume paused data ingestion pipelines or dequeue per-client backlog buffers.
- Code SHOULD enforce a high-water mark (e.g., 64 KiB or 512 KiB) on `ws.getBufferedAmount()` and either drop ephemeral/conflated messages or terminate egregiously slow clients (via `ws.close(1008, 'Policy Violation: Buffer Exceeded')`) to defend global process stability.
- Components NEVER buffer unbounded arrays in memory per client; per-client queues must enforce a strictly bounded ring buffer or discard policy when backpressure thresholds are tripped.

## Bad vs Good Implementations
### WebSocket Fan-Out Broadcast with Auto-Pacing and Drain Monitoring

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Ignoring ws.send() returns and omitting the websocket drain hook allows lagging clients to balloon process heap allocations. Unconsumed socket buffers grow until the Bun runtime crashes with out-of-memory.
```typescript
import { ServerWebSocket } from 'bun';

interface ClientData {
  id: string;
}

const clients = new Set<ServerWebSocket<ClientData>>();

export function broadcastMarketTick(data: Uint8Array): void {
  // ANTI-PATTERN: Fire-and-forget broadcast over all connected sockets.
  // If one slow client or constrained network path stalls, Bun is forced
  // to buffer chunks indefinitely in memory, resulting in runaway RAM consumption and OOM.
  for (const ws of clients) {
    ws.send(data); // Return value ignored, bufferedAmount unchecked
  }
}

Bun.serve<ClientData>({
  port: 8080,
  websocket: {
    open(ws) {
      clients.add(ws);
    },
    message(ws, msg) {},
    close(ws) {
      clients.delete(ws);
    }
    // Missing 'drain' hook
  },
  fetch(req, server) {
    server.upgrade(req, { data: { id: crypto.randomUUID() } });
    return new Response('Upgrade failed', { status: 400 });
  }
});
```

#### Production Standard (Correct)
> **Standard**: Implements proactive backpressure thresholds with ws.getBufferedAmount(), enforces client disconnection at the hard memory boundary, integrates the Bun drain hook to resume transmission, and prevents runaway memory accumulation.
```typescript
import { ServerWebSocket } from 'bun';

interface ClientData {
  id: string;
  isPaused: boolean;
}

const HIGH_WATER_MARK_BYTES = 512 * 1024; // 512 KiB threshold
const MAX_BUFFER_HARD_LIMIT = 2 * 1024 * 1024; // 2 MiB disconnect threshold
const clients = new Set<ServerWebSocket<ClientData>>();

export function broadcastMarketTick(data: Uint8Array): void {
  for (const ws of clients) {
    const currentBuffer = ws.getBufferedAmount();

    // Hard limit breach: disconnect abusive or stalled client to protect the process
    if (currentBuffer > MAX_BUFFER_HARD_LIMIT) {
      ws.close(1008, 'Buffer overflow: Client consuming too slowly');
      clients.delete(ws);
      continue;
    }

    // Backpressure auto-pacing: skip or conflate non-essential updates for backlogged sockets
    if (currentBuffer > HIGH_WATER_MARK_BYTES) {
      ws.data.isPaused = true;
      continue; // Drop ephemeral tick or route to bounded conflation buffer
    }

    // ws.send returns the number of bytes sent or buffered, or -1 on failure
    const sendResult = ws.send(data);
    if (sendResult < 0 || ws.getBufferedAmount() > HIGH_WATER_MARK_BYTES) {
      ws.data.isPaused = true;
    }
  }
}

Bun.serve<ClientData>({
  port: 8080,
  websocket: {
    open(ws) {
      ws.data = { id: crypto.randomUUID(), isPaused: false };
      clients.add(ws);
    },
    message(ws, msg) {
      // Client message ingestion logic
    },
    drain(ws) {
      // Sockets notify when kernel buffer drains below threshold
      if (ws.getBufferedAmount() < HIGH_WATER_MARK_BYTES) {
        ws.data.isPaused = false;
      }
    },
    close(ws) {
      clients.delete(ws);
    }
  },
  fetch(req, server) {
    if (server.upgrade(req, { data: { id: '', isPaused: false } })) {
      return undefined;
    }
    return new Response('WebSocket upgrade required', { status: 426 });
  }
});
```

Recommended MCP Servers (mcp-serverlist.com)

Equip agent with system tools to verify code for this stack.

Architectural Specification & Invariant Rationale

Architectural Invariant Design: Bun 1.2 WebSocket Dynamic Backpressure Auto-Pacing Standard

Bun 1.2 WebSocket Dynamic Backpressure Auto-Pacing Standard defines an industrial-grade behavioral standard for backend engineering. Enforces strict socket-level backpressure management during high-throughput WebSocket broadcast and fan-out operations in Bun 1.2+. Eliminates unconstrained heap memory growth and OOM crashes by monitoring `ws.getBufferedAmount()` and suspending publisher pipelines until the `drain` event clears the kernel network buffer. Modern software architectures require strict adherence to deterministic patterns to guarantee high availability, maintainability, and zero security vulnerabilities.

Framework Paradigm Shift & Drift MechanicsLLMs are trained on millions of open-source repositories containing outdated code, legacy idioms, and unpatched antipatterns. When coding assistants generate implementations for this stack, they default to common statistical tokens: Unchecked Fire-and-Forget Broadcast Loops Causing Heap Exhaustion Under Slow Clients Without an explicit system instruction file, developers spend hours debugging silent failures.
Failure Modes & Production Blast Radius

Hazard Analysis: What Breaks Without This Rule

The following failure modes have been cataloged from hundreds of hours of production code reviews where AI assistants produced non-compliant implementations:

Failure ModeAI Symptom (The Anti-Pattern)SeverityProduction Impact & Remedy
AI Hallucination & Deprecation DriftUnchecked Fire-and-Forget Broadcast Loops Causing Heap Exhaustion Under Slow ClientsCritical
Violating this industrial standard introduces regression bugs, security risks, and unexpected runtime failures in production.
Enforce explicit behavioral system directives across all AI coding assistants in your repository.
Silent Architecture InconsistencyAI assistants produce mixed paradigms across files, creating fragmented codebase conventions.Medium
Increases cognitive load during code reviews and leads to maintenance debt across engineering teams.
Pin project conventions in .cursor/rules, CLAUDE.md, and AGENTS.md so all team agents follow identical guardrails.
Architectural Directives in Detail

Step-by-Step Production Directives

Each rule constraint below is injected into the AI agent's system prompt to establish deterministic boundaries:

1

Engineers MUST ALWAYS verify the numeric return value of `ws.send(data)` or inspect `ws.getBufferedAmount()` prior to enqueuing subsequent frames in publisher loops.

Engineers MUST ALWAYS verify the numeric return value of `ws.send(data)` or inspect `ws.getBufferedAmount()` prior to enqueuing subsequent frames in publisher loops.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
2

Engineers MUST NOT rely on synchronous `for` or `forEach` loops over subscribers when dispatching high-frequency telemetry, market data, or fan-out payloads without per-socket buffer threshold checks.

Engineers MUST NOT rely on synchronous `for` or `forEach` loops over subscribers when dispatching high-frequency telemetry, market data, or fan-out payloads without per-socket buffer threshold checks.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
3

Services MUST implement the `drain(ws)` socket lifecycle hook in `Bun.serve({ websocket

Services MUST implement the `drain(ws)` socket lifecycle hook in `Bun.serve({ websocket: { drain(ws) { ... } } })` to resume paused data ingestion pipelines or dequeue per-client backlog buffers.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
4

Code SHOULD enforce a high-water mark (e.g., 64 KiB or 512 KiB) on `ws.getBufferedAmount()` and either drop ephemeral/conflated messages or terminate egregiously slow clients (via `ws.close(1008, 'Policy Violation

Code SHOULD enforce a high-water mark (e.g., 64 KiB or 512 KiB) on `ws.getBufferedAmount()` and either drop ephemeral/conflated messages or terminate egregiously slow clients (via `ws.close(1008, 'Policy Violation: Buffer Exceeded')`) to defend global process stability.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
5

Components NEVER buffer unbounded arrays in memory per client

Components NEVER buffer unbounded arrays in memory per client; per-client queues must enforce a strictly bounded ring buffer or discard policy when backpressure thresholds are tripped.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
Technical Questions & Answers

Frequently Asked Technical Questions

Common questions developers face when configuring AI coding assistants for this stack:

Q:Why is Bun 1.2 WebSocket Dynamic Backpressure Auto-Pacing Standard critical for AI coding assistants?

Enforces strict socket-level backpressure management during high-throughput WebSocket broadcast and fan-out operations in Bun 1.2+. Eliminates unconstrained heap memory growth and OOM crashes by monitoring `ws.getBufferedAmount()` and suspending publisher pipelines until the `drain` event clears the kernel network buffer. Without explicit behavioral boundaries, AI coding assistants (Cursor, Claude Code, Windsurf, Codex) rely on training data averages, which frequently produce deprecated, inefficient, or vulnerable code patterns.

Q:How does adopting this rule prevent AI hallucinations?

This rule explicitly declares what the AI must avoid (Unchecked Fire-and-Forget Broadcast Loops Causing Heap Exhaustion Under Slow Clients) and prescribes verified positive examples. Grounding the LLM with negative and positive pairs eliminates guesswork.

Q:Which AI coding environments are supported?

This specification is multi-platform compatible: Cursor (.cursor/rules/*.mdc & .cursorrules), Anthropic Claude Code (CLAUDE.md), Windsurf (.windsurfrules), Codex / Cline (AGENTS.md), and GitHub Copilot (.github/copilot-instructions.md).

Q:Can I combine this rule with other technology stacks?

Yes. Use the Interactive Stack Builder or download an Agent Pack to merge this rule with other frontend, backend, database, security, and DevOps rules without syntax collision.

Open Specification · CC BY 4.0·Free for Personal, Team & Commercial In-Repo Use

Citation & Open Source Attribution Guidelines

This specification is licensed under Creative Commons Attribution 4.0 International (CC BY 4.0). You are completely free to adapt and share this rule in your workspace. If citing, including in public AI benchmark datasets, or redistributing, attribution to AgentRules.org is required.

1 Rule in Stack

Bun