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

Bun 1.2 Native WebSocket Low-Watermark Backpressure Invariant

Enforces strict producer suspension and deterministic TCP drain coordination for Bun 1.2 native WebSockets using low/high watermark thresholds on `ws.bufferedAmount`. Prevents unbounded V8/JSC heap exhaustion caused by slow socket consumers during high-throughput binary and text streaming. Mandates cooperative yielding via the native `drain(ws)` socket lifecycle hook rather than fire-and-forget message dispatching.

Prohibited Anti-Pattern: Unbounded Fire-and-Forget `ws.send()` Dispatching Ignoring Native `bufferedAmount` Accumulation

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Bun 1.2 Native WebSocket Low-Watermark Backpressure Invariant - Enforces strict producer suspension and deterministic TCP drain coordination for Bun 1.2 native WebSockets using low/high watermark thresholds on `ws.bufferedAmount`. Prevents unbounded V8/JSC heap exhaustion caused by slow socket consumers during high-throughput binary and text streaming. Mandates cooperative yielding via the native `drain(ws)` socket lifecycle hook rather than fire-and-forget message dispatching.
globs: src/**/*.{ts,tsx}, server/**/*.{ts,tsx}
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/bun-websocket-low-watermark-backpressure-invariant"
---

# Bun 1.2 Native WebSocket Low-Watermark Backpressure Invariant

> **Severity**: CRITICAL | **Category**: backend
> **Anti-Pattern Warning**: Unbounded Fire-and-Forget `ws.send()` Dispatching Ignoring Native `bufferedAmount` Accumulation

## System Constraints
You are a Principal Engineer enforcing the Bun 1.2 Native WebSocket Low-Watermark Backpressure Invariant. Under Bun's native uSockets layer, `ws.send()` queues packets directly into userspace/kernel buffers. Disregarding `ws.bufferedAmount` and omitting `drain(ws)` lifecycle handlers creates unbounded memory leaks and event loop starvation when downstream bandwidth degrades. You must strictly mandate producer suspension when `bufferedAmount` breaches the high watermark (e.g., 512KB) and resume only when the low watermark (e.g., 64KB) is reached via `drain`.

## Strict Guidelines
- Engineers MUST ALWAYS implement the `drain(ws)` hook on Bun's WebSocket handler when streaming high-frequency data or large payloads.
- Engineers MUST ALWAYS verify `ws.bufferedAmount` before invoking `ws.send()` in streaming loops or asynchronous generators.
- Engineers MUST pause producer ingestion and park the dispatch routine when `ws.bufferedAmount` exceeds the high-watermark threshold (default: 512 KiB).
- Engineers MUST resume paused producers only when `ws.bufferedAmount` falls below the low-watermark threshold (default: 64 KiB), signaled by the native `drain(ws)` callback.
- Engineers MUST NOT create unbounded in-memory promise queues or async dispatch loops that invoke `ws.send()` without awaiting drain synchronization.
- Services MUST abort or forcefully close client connections (`ws.close(1008, 'Slow Consumer')`) if backpressure suspension times out or exceeds hard buffer ceiling limits (e.g., 16 MiB).

## Bad vs Good Implementations
### High-Throughput WebSocket Producer with Watermark Backpressure and Drain Coordination

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Invoking ws.send() unconditionally inside an async iterator ignores client link degradation. Unsent bytes continuously accumulate in Bun's uSockets buffer, leading to process OOM crashes under high-load streaming.
```typescript
import type { ServerWebSocket } from "bun";

// ANTI-PATTERN: Fire-and-forget push ignoring native socket buffer pressure.
// If the client's network link is saturated, bufferedAmount grows unbounded,
// exhausting the Bun runtime memory and crashing the process.
export async function streamMetricsToClient(
  ws: ServerWebSocket<unknown>,
  dataSource: AsyncIterable<Uint8Array>
): Promise<void> {
  for await (const chunk of dataSource) {
    // ws.send returns the number of bytes sent or queued, but does not wait for TCP ACK
    ws.send(chunk);
  }
}
```

#### Production Standard (Correct)
> **Standard**: Implements an explicit producer-consumer backpressure contract using `HIGH_WATERMARK` and `LOW_WATERMARK`. Suspends the `for-await` producer loop via an awaitable promise, which is deterministically resolved inside Bun's native `drain(ws)` handler only after the socket buffer recedes below `LOW_WATERMARK`.
```typescript
import type { ServerWebSocket, WebSocketHandler } from "bun";

interface SocketData {
  drainResolver: (() => void) | null;
  isPaused: boolean;
}

const HIGH_WATERMARK = 512 * 1024; // 512 KiB: Pause upstream producer
const LOW_WATERMARK = 64 * 1024;   // 64 KiB: Resume upstream producer

export const wsHandler: WebSocketHandler<SocketData> = {
  open(ws) {
    ws.data = { drainResolver: null, isPaused: false };
  },
  message(ws, message) {
    // Normal message handling...
  },
  drain(ws) {
    // Fired by Bun when the native kernel buffer drains
    if (ws.bufferedAmount <= LOW_WATERMARK && ws.data.drainResolver) {
      const resolve = ws.data.drainResolver;
      ws.data.drainResolver = null;
      ws.data.isPaused = false;
      resolve();
    }
  },
  close(ws) {
    if (ws.data.drainResolver) {
      ws.data.drainResolver();
      ws.data.drainResolver = null;
    }
  }
};

export async function streamMetricsToClient(
  ws: ServerWebSocket<SocketData>,
  dataSource: AsyncIterable<Uint8Array>
): Promise<void> {
  for await (const chunk of dataSource) {
    if (ws.readyState !== 1) break;

    // Backpressure check: Suspend producer if high watermark is reached
    if (ws.bufferedAmount >= HIGH_WATERMARK) {
      ws.data.isPaused = true;
      await new Promise<void>((resolve) => {
        ws.data.drainResolver = resolve;
      });
    }

    if (ws.readyState !== 1) break;
    ws.send(chunk);
  }
}
```

Recommended MCP Servers (mcp-serverlist.com)

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

Recommended Agent Skills (askills.dev)

Ready-to-use executable skill functions tailored to this stack.

Architectural Specification & Invariant Rationale

Architectural Invariant Design: Bun 1.2 Native WebSocket Low-Watermark Backpressure Invariant

Bun 1.2 Native WebSocket Low-Watermark Backpressure Invariant defines an industrial-grade behavioral standard for backend engineering. Enforces strict producer suspension and deterministic TCP drain coordination for Bun 1.2 native WebSockets using low/high watermark thresholds on `ws.bufferedAmount`. Prevents unbounded V8/JSC heap exhaustion caused by slow socket consumers during high-throughput binary and text streaming. Mandates cooperative yielding via the native `drain(ws)` socket lifecycle hook rather than fire-and-forget message dispatching. 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: Unbounded Fire-and-Forget `ws.send()` Dispatching Ignoring Native `bufferedAmount` Accumulation 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 DriftUnbounded Fire-and-Forget `ws.send()` Dispatching Ignoring Native `bufferedAmount` AccumulationCritical
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 implement the `drain(ws)` hook on Bun's WebSocket handler when streaming high-frequency data or large payloads.

Engineers MUST ALWAYS implement the `drain(ws)` hook on Bun's WebSocket handler when streaming high-frequency data or large payloads.

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 ALWAYS verify `ws.bufferedAmount` before invoking `ws.send()` in streaming loops or asynchronous generators.

Engineers MUST ALWAYS verify `ws.bufferedAmount` before invoking `ws.send()` in streaming loops or asynchronous generators.

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

Engineers MUST pause producer ingestion and park the dispatch routine when `ws.bufferedAmount` exceeds the high-watermark threshold (default

Engineers MUST pause producer ingestion and park the dispatch routine when `ws.bufferedAmount` exceeds the high-watermark threshold (default: 512 KiB).

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

Engineers MUST resume paused producers only when `ws.bufferedAmount` falls below the low-watermark threshold (default

Engineers MUST resume paused producers only when `ws.bufferedAmount` falls below the low-watermark threshold (default: 64 KiB), signaled by the native `drain(ws)` callback.

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

Engineers MUST NOT create unbounded in-memory promise queues or async dispatch loops that invoke `ws.send()` without awaiting drain synchronization.

Engineers MUST NOT create unbounded in-memory promise queues or async dispatch loops that invoke `ws.send()` without awaiting drain synchronization.

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.
6

Services MUST abort or forcefully close client connections (`ws.close(1008, 'Slow Consumer')`) if backpressure suspension times out or exceeds hard buffer ceiling limits (e.g., 16 MiB).

Services MUST abort or forcefully close client connections (`ws.close(1008, 'Slow Consumer')`) if backpressure suspension times out or exceeds hard buffer ceiling limits (e.g., 16 MiB).

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 Native WebSocket Low-Watermark Backpressure Invariant critical for AI coding assistants?

Enforces strict producer suspension and deterministic TCP drain coordination for Bun 1.2 native WebSockets using low/high watermark thresholds on `ws.bufferedAmount`. Prevents unbounded V8/JSC heap exhaustion caused by slow socket consumers during high-throughput binary and text streaming. Mandates cooperative yielding via the native `drain(ws)` socket lifecycle hook rather than fire-and-forget message dispatching. 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 (Unbounded Fire-and-Forget `ws.send()` Dispatching Ignoring Native `bufferedAmount` Accumulation) 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