Bali, Indonesia
Insights

Running Bun in Production: Linux Kernel Tuning and Systemd Sandboxing for High-Concurrency JS Runtimes

October 12, 2026
The JavaScript ecosystem has undergone a paradigm shift with the maturation of native, highly optimized runtimes built on Zig and custom execution loops. Moving away from traditional Node.js deployments requires a fundamental rethinking of how underlying Linux systems manage resources, system calls, and concurrency. When pushing a modern runtime like Bun to its absolute limits, default kernel configurations and standard systemd unit files often act as artificial bottlenecks, causing unexpected socket exhaustion, silent file descriptor drops, and suboptimal memory usage under heavy load.
Traditional Node.js applications rely heavily on the V8 engine and libuv for asynchronous I/O multiplexing. Bun diverges significantly by utilizing a custom JavaScript engine implementation and an optimized system-call layer that interacts closely with modern Linux kernel primitives. Because Bun can handle massive connection volumes per single process, it frequently triggers operating system limits long before CPU saturation occurs. Consider the default limits imposed by systemd and standard Linux distributions. A typical server setup restricts individual user slices to 1024 open file descriptors. Under high-throughput HTTP/1.1 and HTTP/2 traffic, a single Bun worker process handling persistent keep-alive connections will exhaust this limit almost instantly, resulting in 'EMFILE: too many open files' errors.
Resource TypeDefault Linux / systemd LimitProduction Recommended LimitImpact of Misconfiguration
Open File Descriptors10241048576Connection drops, EMFILE errors
Max Queued Connections (somaxconn)12865535Connection timeouts, SYN packet drops
Virtual Memory Map Areas65530524288Out-of-memory crashes under heavy heap sizing
Process Thread Limits750065535Failure to spawn worker threads
Deploying a production web application requires treating the service daemon with rigorous isolation. Below is an enterprise-grade systemd service definition designed for Bun applications, incorporating strict resource limits, security sandboxing, and optimized process management.
[Unit]
Description=High-Performance Bun HTTP Microservice
After=network.target remote-fs.target nss-lookup.target

[Service]
Type=notify
User=www-data
Group=www-data
WorkingDirectory=/var/www/api
ExecStart=/usr/local/bin/bun run start:prod
Restart=always
RestartSec=5

# Resource Limits
LimitNOFILE=1048576
LimitNPROC=65535
LimitMEMLOCK=infinity
TasksMax=infinity

# Security Hardening & Sandboxing
ProtectSystem=strict
ProtectHome=true
NoNewPrivileges=true
PrivateTmp=true
ReadWritePaths=/var/www/api/logs /var/www/api/tmp

# Performance Tuning
CPUSchedulingPolicy=other
Nice=-5
StandardOutput=journal
StandardError=journal
SyslogIdentifier=bun-api

[Install]
WantedBy=multi-user.target
Save this configuration to '/etc/systemd/system/bun-api.service', reload the daemon via 'systemctl daemon-reload', and enable the service using 'systemctl enable --now bun-api.service'.
Even with an optimized systemd service file, the Linux networking stack will drop packets if the kernel buffers are undersized. To handle extreme concurrency, modify your '/etc/sysctl.conf' or create a dedicated drop-in file under '/etc/sysctl.d/99-bun-performance.conf'.
# Increase maximum socket receive and send buffers
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216

# Expand the backlog queue for incoming TCP connections
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535

# Enable TCP fast open and reuse time-wait sockets safely
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15

# Increase maximum virtual memory mappings
vm.max_map_count = 524288
Apply these configurations immediately without rebooting the host using the command 'sysctl --system'.
Unlike Node.js, which exposes V8-specific flags like '--max-old-space-size', Bun's internal memory management behaves differently due to its focus on raw performance and minimal overhead. However, when running memory-intensive operations, configuring process memory limits inside systemd via 'MemoryMax' and 'MemoryHigh' ensures that a rogue memory leak does not trigger an unconstrained kernel OOM killer event that takes down the entire node. Add the following directives to the '[Service]' block of your systemd unit file when managing strict memory quotas on dedicated hosting infrastructure:
MemoryHigh=12G
MemoryMax=14G
OOMPolicy=continue
OOMScoreAdjust=-500
Setting 'OOMPolicy=continue' instructs systemd to log the out-of-memory condition rather than immediately terminating the service, allowing monitoring agents to capture telemetry while the process attempts to recover.
Once deployed, verify that your limits are correctly applied to the running process by inspecting the proc filesystem. Execute 'cat /proc/$(pgrep -u www-data bun | head -n 1)/limits' to ensure that 'Max open files' reflects '1048576'. To benchmark the new setup, avoid using rudimentary tools that exhaust local ephemeral ports incorrectly. Use modern HTTP benchmarking utilities such as 'wrk' or 'hey' configured with persistent connections enabled:
hey -z 30s -c 500 -H 'Connection: keep-alive' https://api.local/health
Monitor real-time system performance using 'htop' or structured logging via 'journalctl -u bun-api.service -f' to track latency percentiles and verify that zero connection drops occur under peak load.