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

Bun 1.2 Native WebSocket Hibernation & Backpressure Drainage Policy

Enforces Bun 1.2 native WebSocket server invariants by delegating idle connection state to the native C++ event loop via WebSocket Hibernation and strictly handling TCP backpressure during packet transmission. Prevents V8 heap exhaustion and silent message dropping under high-concurrency loads (100k+ concurrent connections) by forbidding JavaScript closure retention on socket instances and requiring drain-driven writes.

Prohibited Anti-Pattern: Retaining JavaScript WebSocket References in Userland State and Ignoring ws.send() Backpressure Return Codes

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Bun 1.2 Native WebSocket Hibernation & Backpressure Drainage Policy - Enforces Bun 1.2 native WebSocket server invariants by delegating idle connection state to the native C++ event loop via WebSocket Hibernation and strictly handling TCP backpressure during packet transmission. Prevents V8 heap exhaustion and silent message dropping under high-concurrency loads (100k+ concurrent connections) by forbidding JavaScript closure retention on socket instances and requiring drain-driven writes.
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-hibernation-backpressure-drainage-policy"
---

# Bun 1.2 Native WebSocket Hibernation & Backpressure Drainage Policy

> **Severity**: CRITICAL | **Category**: backend
> **Anti-Pattern Warning**: Retaining JavaScript WebSocket References in Userland State and Ignoring ws.send() Backpressure Return Codes

## System Constraints
You are a Principal Backend Architect enforcing Bun 1.2 Native WebSocket Hibernation and Backpressure Drainage invariants. In Bun, WebSockets must leverage native C++ hibernation to achieve sub-gigabyte memory footprints for 100k+ concurrent connections. You must reject any code storing WebSocket instances in userland Maps/Sets, mandate attaching serializable per-socket metadata strictly through the upgrade handler's `data` payload, and enforce handling of `ws.send()` numeric return codes via the `drain` callback to prevent unbounded outbound buffer growth.

## Strict Guidelines
- Engineers MUST ALWAYS configure `Bun.serve` with native `websocket` handler hooks (`open`, `message`, `close`, `drain`) rather than instantiating non-native third-party WebSocket libraries.
- Engineers MUST NOT store `ServerWebSocket` object references in userland collections (e.g., `new Map<string, ServerWebSocket>()`, `new Set()`, arrays, or object properties), as doing so prevents the Bun C++ runtime from sweeping the V8 wrapper and hibernating the socket.
- Engineers MUST ALWAYS pass connection state through the `data` property of `server.upgrade(req, { data: { ... } })`, typing the socket using `ServerWebSocket<SocketDataType>`.
- Engineers MUST ALWAYS evaluate the integer return value of `ws.send(data)`: if `ws.send()` returns `0` (dropped) or indicates backpressure (bytes queued exceeds threshold via `ws.getBufferedAmount()`), writes MUST be suspended until the native `drain(ws)` hook executes.
- Services MUST implement a per-socket outbound chunk queue attached to `ws.data` that is flushed exclusively within the `drain(ws)` lifecycle callback.
- Engineers MUST ALWAYS use native Bun topic subscription (`ws.subscribe(topic)` and `server.publish(topic, message)`) for broadcasting, completely avoiding manual iteration over userland socket sets.

## Bad vs Good Implementations
### Naive Userland Socket Registry vs. Native Hibernation with Drain Backpressure

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Storing `ServerWebSocket` instances in `activeSockets` defeats Bun 1.2's WebSocket Hibernation. Under 100k idle connections, this retains millions of V8 wrapper objects in heap, inducing extreme GC pressure and OOM crashes. Additionally, ignoring `ws.send()` return codes discards data under network congestion when the kernel transmit queue saturates.
```typescript
import { type ServerWebSocket } from "bun";

interface ClientData {
  userId: string;
}

// ANTI-PATTERN: Holding direct JS references prevents Bun C++ socket hibernation
const activeSockets = new Map<string, ServerWebSocket<ClientData>>();

Bun.serve<ClientData>({
  port: 8080,
  fetch(req, server) {
    const userId = new URL(req.url).searchParams.get("userId");
    if (!userId) return new Response("Unauthorized", { status: 401 });

    const success = server.upgrade(req, { data: { userId } });
    return success ? undefined : new Response("Upgrade failed", { status: 400 });
  },
  websocket: {
    open(ws) {
      // Retaining the JS wrapper in a Map pins the entire context in V8 heap
      activeSockets.set(ws.data.userId, ws);
    },
    message(ws, message) {
      // ANTI-PATTERN: Iterating userland collection and ignoring backpressure
      for (const [id, socket] of activeSockets) {
        // Ignores return value of send; risks silent packet loss and memory inflation
        socket.send(`Broadcast: ${message}`);
      }
    },
    close(ws) {
      activeSockets.delete(ws.data.userId);
    }
  }
});
```

#### Production Standard (Correct)
> **Standard**: This implementation fully leverages Bun 1.2's native C++ hibernation. Idle sockets drop out of V8 heap into the C++ kernel event loop because no userland collection stores references to them. Group broadcasts are dispatched via Bun's native `ws.subscribe` / `ws.publish` routines, and outbound messaging strictly observes backpressure via `drain(ws)` and `pendingQueue` tracking.
```typescript
import { type ServerWebSocket } from "bun";

interface WebSocketData {
  userId: string;
  topic: string;
  pendingQueue: Uint8Array[];
}

const BROADCAST_TOPIC = "global_broadcast";

Bun.serve<WebSocketData>({
  port: 8080,
  fetch(req, server) {
    const userId = new URL(req.url).searchParams.get("userId");
    if (!userId) return new Response("Unauthorized", { status: 401 });

    const upgraded = server.upgrade(req, {
      data: {
        userId,
        topic: BROADCAST_TOPIC,
        pendingQueue: []
      }
    });
    return upgraded ? undefined : new Response("Upgrade failed", { status: 400 });
  },
  websocket: {
    // Native hibernation enabled: zero userland JS references are stored outside ws.data
    open(ws) {
      ws.subscribe(ws.data.topic);
    },
    message(ws, message) {
      const payload = typeof message === "string" ? Buffer.from(message) : message;
      // Use native C++ Pub/Sub engine instead of manual socket iteration
      ws.publish(ws.data.topic, payload);
    },
    drain(ws) {
      // BACKPRESSURE DRAINAGE POLICY: Flush queued packets once TCP buffer accepts writes
      while (ws.data.pendingQueue.length > 0) {
        const nextChunk = ws.data.pendingQueue[0];
        // ws.send returns number of bytes written; 0 indicates buffer full/backpressure
        const bytesSent = ws.send(nextChunk);
        if (bytesSent === 0) {
          return; // Still congested; wait for next drain event
        }
        ws.data.pendingQueue.shift();
      }
    },
    close(ws) {
      ws.unsubscribe(ws.data.topic);
      ws.data.pendingQueue = [];
    }
  }
});
```

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 Hibernation & Backpressure Drainage Policy

Bun 1.2 Native WebSocket Hibernation & Backpressure Drainage Policy defines an industrial-grade behavioral standard for backend engineering. Enforces Bun 1.2 native WebSocket server invariants by delegating idle connection state to the native C++ event loop via WebSocket Hibernation and strictly handling TCP backpressure during packet transmission. Prevents V8 heap exhaustion and silent message dropping under high-concurrency loads (100k+ concurrent connections) by forbidding JavaScript closure retention on socket instances and requiring drain-driven writes. 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: Retaining JavaScript WebSocket References in Userland State and Ignoring ws.send() Backpressure Return Codes 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 DriftRetaining JavaScript WebSocket References in Userland State and Ignoring ws.send() Backpressure Return CodesCritical
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 configure `Bun.serve` with native `websocket` handler hooks (`open`, `message`, `close`, `drain`) rather than instantiating non-native third-party WebSocket libraries.

Engineers MUST ALWAYS configure `Bun.serve` with native `websocket` handler hooks (`open`, `message`, `close`, `drain`) rather than instantiating non-native third-party WebSocket libraries.

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 store `ServerWebSocket` object references in userland collections (e.g., `new Map<string, ServerWebSocket>()`, `new Set()`, arrays, or object properties), as doing so prevents the Bun C++ runtime from sweeping the V8 wrapper and hibernating the socket.

Engineers MUST NOT store `ServerWebSocket` object references in userland collections (e.g., `new Map<string, ServerWebSocket>()`, `new Set()`, arrays, or object properties), as doing so prevents the Bun C++ runtime from sweeping the V8 wrapper and hibernating the socket.

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 ALWAYS pass connection state through the `data` property of `server.upgrade(req, { data

Engineers MUST ALWAYS pass connection state through the `data` property of `server.upgrade(req, { data: { ... } })`, typing the socket using `ServerWebSocket<SocketDataType>`.

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 ALWAYS evaluate the integer return value of `ws.send(data)`

Engineers MUST ALWAYS evaluate the integer return value of `ws.send(data)`: if `ws.send()` returns `0` (dropped) or indicates backpressure (bytes queued exceeds threshold via `ws.getBufferedAmount()`), writes MUST be suspended until the native `drain(ws)` hook executes.

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

Services MUST implement a per-socket outbound chunk queue attached to `ws.data` that is flushed exclusively within the `drain(ws)` lifecycle callback.

Services MUST implement a per-socket outbound chunk queue attached to `ws.data` that is flushed exclusively within the `drain(ws)` lifecycle 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.
6

Engineers MUST ALWAYS use native Bun topic subscription (`ws.subscribe(topic)` and `server.publish(topic, message)`) for broadcasting, completely avoiding manual iteration over userland socket sets.

Engineers MUST ALWAYS use native Bun topic subscription (`ws.subscribe(topic)` and `server.publish(topic, message)`) for broadcasting, completely avoiding manual iteration over userland socket sets.

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 Hibernation & Backpressure Drainage Policy critical for AI coding assistants?

Enforces Bun 1.2 native WebSocket server invariants by delegating idle connection state to the native C++ event loop via WebSocket Hibernation and strictly handling TCP backpressure during packet transmission. Prevents V8 heap exhaustion and silent message dropping under high-concurrency loads (100k+ concurrent connections) by forbidding JavaScript closure retention on socket instances and requiring drain-driven writes. 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 (Retaining JavaScript WebSocket References in Userland State and Ignoring ws.send() Backpressure Return Codes) 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