This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
backendcritical PriorityID: bun-explicit-resource-management-fd-boundary

Bun 1.2 TC39 Explicit Resource Management (Symbol.asyncDispose) FD Boundary

Enforces strict utilization of TC39 Explicit Resource Management via 'using' and 'await using' declarations across Bun 1.2+ runtime boundaries. Eliminates file descriptor (FD) and OS handle leakage across high-throughput Bun TCP sockets, FileSink streams, and bun:sqlite database handles during unhandled exceptions and early return flows.

Prohibited Anti-Pattern: Implicit garbage-collection-dependent teardown of native OS file descriptors causing EMFILE pool exhaustion under load

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Bun 1.2 TC39 Explicit Resource Management (Symbol.asyncDispose) FD Boundary - Enforces strict utilization of TC39 Explicit Resource Management via 'using' and 'await using' declarations across Bun 1.2+ runtime boundaries. Eliminates file descriptor (FD) and OS handle leakage across high-throughput Bun TCP sockets, FileSink streams, and bun:sqlite database handles during unhandled exceptions and early return flows.
globs: src/**/*.{ts,tsx}
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/bun-explicit-resource-management-fd-boundary"
---

# Bun 1.2 TC39 Explicit Resource Management (Symbol.asyncDispose) FD Boundary

> **Severity**: CRITICAL | **Category**: backend
> **Anti-Pattern Warning**: Implicit garbage-collection-dependent teardown of native OS file descriptors causing EMFILE pool exhaustion under load

## System Constraints
You are a Principal Backend Architect enforcing strict system-level resource containment in Bun 1.2+. You mandate the TC39 Explicit Resource Management standard (`using` and `await using` with `Symbol.dispose` and `Symbol.asyncDispose`) for all OS-bound handles, including native Bun TCP/TLS socket connections, FileSink file streams, and SQLite connection/statement handles. Prevent unmanaged handles from lingering in the V8/JSC garbage collection queue and causing EMFILE errors.

## Strict Guidelines
- Engineers MUST ALWAYS bind SQLite transactions, prepared statement iterators, and temporary database instances to `using` or `await using` scopes containing an explicit `Symbol.dispose` or `Symbol.asyncDispose` contract.
- Engineers MUST NOT rely on runtime finalizers, unconstrained `try...finally` manual teardowns without deterministic unwinding, or GC cycles to release underlying OS file descriptors in Bun services.
- Code SHOULD wrap raw `Bun.connect()`, `Bun.file().writer()`, and external network stream interfaces in custom disposable wrappers implementing `[Symbol.asyncDispose]()` if native disposable interfaces are not directly exposed.
- Services MUST compile with TypeScript `target` or `lib` configured to include `esnext.disposable` to guarantee type-safety and correct stack unwinding emit semantics.
- Components NEVER capture un-disposed socket or stream references inside detached background microtasks without deterministic lifespan ownership passed to an explicit `AsyncDisposableStack`.

## Bad vs Good Implementations
### Bun SQLite Connection and Statement Scope Containment

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: If the processing loop throws, db.close() is never invoked. The native file descriptor remains open until Bun's garbage collector runs finalizers, exhausting the operating system's ulimit under load.
```typescript
import { Database } from 'bun:sqlite';

export async function processTenantData(dbPath: string, payload: unknown[]) {
  // Anti-pattern: Database handle relies on GC finalizer; unhandled errors leak FD
  const db = new Database(dbPath, { create: false });
  const stmt = db.prepare('INSERT INTO audit_log (data) VALUES (?1)');
  
  for (const item of payload) {
    if (typeof item !== 'object') {
      throw new Error('Corrupted payload'); // db handle leaks indefinitely in memory pool
    }
    stmt.run(JSON.stringify(item));
  }
  
  db.close();
}
```

#### Production Standard (Correct)
> **Standard**: Using the 'using' declaration guarantees that both the prepared statement and the native SQLite database file descriptor are closed deterministically at the exit of the function block, even on error.
```typescript
import { Database } from 'bun:sqlite';

// Production Invariant: Wrap Database in a disposable resource contract
class DisposableDatabase extends Database implements Disposable {
  [Symbol.dispose]() {
    this.close();
  }
}

export async function processTenantData(dbPath: string, payload: unknown[]) {
  // Deterministic teardown guaranteed upon block exit, even on thrown exceptions
  using db = new DisposableDatabase(dbPath, { create: false });
  const stmt = db.prepare('INSERT INTO audit_log (data) VALUES (?1)');
  
  using _ = {
    [Symbol.dispose]() {
      stmt.finalize();
    }
  };

  for (const item of payload) {
    if (typeof item !== 'object') {
      throw new Error('Corrupted payload');
    }
    stmt.run(JSON.stringify(item));
  }
}
```

### Bun TCP Socket and Stream Disposal with AsyncDisposableStack

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: If network partition occurs, socket.write() or socket.flush() can fail or stall without deterministic resource cleanup, leaking the socket FD in the event loop.
```typescript
export async function replicateStream(targetHost: string, data: Uint8Array) {
  // Anti-pattern: Manual socket lifecycle tracking prone to hanging FDs on aborted writes
  const socket = await Bun.connect({
    hostname: targetHost,
    port: 9000,
    socket: {
      data(socket, buffer) {},
      open(socket) {},
      close(socket) {},
      error(socket, error) {}
    }
  });

  socket.write(data);
  socket.flush();
  socket.end();
}
```

#### Production Standard (Correct)
> **Standard**: Using AsyncDisposableStack registers a fail-safe teardown hook that guarantees rawSocket.end() or rawSocket.terminate() will execute on scope exit, shielding the runtime from network FD exhaustion.
```typescript
export async function replicateStream(targetHost: string, data: Uint8Array) {
  await using stack = new AsyncDisposableStack();

  const rawSocket = await Bun.connect({
    hostname: targetHost,
    port: 9000,
    socket: {
      data(socket, buffer) {},
      open(socket) {},
      close(socket) {},
      error(socket, error) {}
    }
  });

  // Register explicit async disposal hook
  stack.defer(async () => {
    try {
      rawSocket.end();
    } catch {
      rawSocket.terminate();
    }
  });

  rawSocket.write(data);
  rawSocket.flush();
}
```

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 TC39 Explicit Resource Management (Symbol.asyncDispose) FD Boundary

Bun 1.2 TC39 Explicit Resource Management (Symbol.asyncDispose) FD Boundary defines an industrial-grade behavioral standard for backend engineering. Enforces strict utilization of TC39 Explicit Resource Management via 'using' and 'await using' declarations across Bun 1.2+ runtime boundaries. Eliminates file descriptor (FD) and OS handle leakage across high-throughput Bun TCP sockets, FileSink streams, and bun:sqlite database handles during unhandled exceptions and early return flows. 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: Implicit garbage-collection-dependent teardown of native OS file descriptors causing EMFILE pool exhaustion under load 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 DriftImplicit garbage-collection-dependent teardown of native OS file descriptors causing EMFILE pool exhaustion under loadCritical
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 bind SQLite transactions, prepared statement iterators, and temporary database instances to `using` or `await using` scopes containing an explicit `Symbol.dispose` or `Symbol.asyncDispose` contract.

Engineers MUST ALWAYS bind SQLite transactions, prepared statement iterators, and temporary database instances to `using` or `await using` scopes containing an explicit `Symbol.dispose` or `Symbol.asyncDispose` contract.

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 runtime finalizers, unconstrained `try...finally` manual teardowns without deterministic unwinding, or GC cycles to release underlying OS file descriptors in Bun services.

Engineers MUST NOT rely on runtime finalizers, unconstrained `try...finally` manual teardowns without deterministic unwinding, or GC cycles to release underlying OS file descriptors in Bun services.

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

Code SHOULD wrap raw `Bun.connect()`, `Bun.file().writer()`, and external network stream interfaces in custom disposable wrappers implementing `[Symbol.asyncDispose]()` if native disposable interfaces are not directly exposed.

Code SHOULD wrap raw `Bun.connect()`, `Bun.file().writer()`, and external network stream interfaces in custom disposable wrappers implementing `[Symbol.asyncDispose]()` if native disposable interfaces are not directly exposed.

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

Services MUST compile with TypeScript `target` or `lib` configured to include `esnext.disposable` to guarantee type-safety and correct stack unwinding emit semantics.

Services MUST compile with TypeScript `target` or `lib` configured to include `esnext.disposable` to guarantee type-safety and correct stack unwinding emit semantics.

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 capture un-disposed socket or stream references inside detached background microtasks without deterministic lifespan ownership passed to an explicit `AsyncDisposableStack`.

Components NEVER capture un-disposed socket or stream references inside detached background microtasks without deterministic lifespan ownership passed to an explicit `AsyncDisposableStack`.

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 TC39 Explicit Resource Management (Symbol.asyncDispose) FD Boundary critical for AI coding assistants?

Enforces strict utilization of TC39 Explicit Resource Management via 'using' and 'await using' declarations across Bun 1.2+ runtime boundaries. Eliminates file descriptor (FD) and OS handle leakage across high-throughput Bun TCP sockets, FileSink streams, and bun:sqlite database handles during unhandled exceptions and early return flows. 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 (Implicit garbage-collection-dependent teardown of native OS file descriptors causing EMFILE pool exhaustion under load) 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