bgr
v3.3.1
Published
Bun: Background Runner - A lightweight process manager written in Bun
Maintainers
Readme
BGR: Background Runner
A powerful process manager built with Bun for managing long-running processes with advanced features like auto-restart, file watching, and integration with Bun's execution model.
Installation
Prerequisites
- Bun v1.0.0 or higher
Install
bun install -g bgr@latestDevelopment
git clone https://github.com/7flash/bgr.git
cd bgr
bun install
bun linkFeatures
- Advanced process management with database persistence
- Auto-restart with file watching for development
- Environment variable management from TOML config files
- Process monitoring and status tracking
- Automatic port cleanup on force restart
- Git integration with automatic pull on
--fetch - Group filtering and JSON output
- Structured logging with custom log paths
Usage
Process Management
# List all processes
bgr
# List processes filtered by group
bgr --filter api
# List processes in JSON format
bgr --json
# View process details
bgr myapp
# Show process logs
bgr myapp --logs --lines 50
# View only stdout logs
bgr myapp --logs --log-stdout
# View only stderr logs
bgr myapp --logs --log-stderrStarting Processes
# Basic process start
bgr --name myapp --directory /path/to/project --command "npm start"
# Start with file watching (auto-restart on changes)
bgr --name myapp --directory ./myapp --command "bun run dev" --watch
# Start with config file for environment variables
bgr --name myapp --directory ./myapp --command "bun run server" --config production.toml
# Force restart (kills existing process and port conflicts)
bgr --name myapp --directory ./myapp --command "bun run server" --force
# Start with automatic git pull
bgr --name myapp --directory ./myapp --command "bun run server" --fetchProcess Control
# Restart process
bgr myapp --restart
# Delete specific process
bgr --delete myapp
# Clean stopped processes
bgr --clean
# Delete ALL processes
bgr --nukeAdvanced Usage
Development with Auto-Restart
BGR excels at development workflows with its --watch mode:
# Frontend development with auto-restart and logs
bgr --name frontend \
--directory ~/projects/frontend \
--command "bun run --watch dev" \
--watch \
--logs \
--log-stdout \
--lines 20
# Backend API with file watching and environment
bgr --name api \
--directory ~/projects/api \
--command "bun run src/server.ts" \
--watch \
--config .config.toml \
--forceProduction Deployment
# Start production service
bgr --name production-api \
--directory /var/www/api \
--command "bun run src/server.ts" \
--config production.toml \
--fetch \
--stdout /var/log/bgr/api-out.log \
--stderr /var/log/bgr/api-err.log
# Multiple services in same group
BGR_GROUP=api bgr --name auth-api --directory ./auth --command "bun run server"
BGR_GROUP=api bgr --name user-api --directory ./users --command "bun run server"
# Filter by group
bgr --filter apiProgrammatic API
BGR exposes its core functions as a regular importable package. Build your own dashboards, orchestrators, or monitoring tools:
bun add bgrimport {
getAllProcesses,
getProcess,
isProcessRunning,
terminateProcess,
handleRun,
getVersion,
calculateRuntime,
readFileTail,
getProcessPorts,
} from 'bgr'Database Operations
import { getAllProcesses, getProcess, removeProcessByName } from 'bgr'
// Get all managed processes
const processes = getAllProcesses()
// Find a specific process by name
const api = getProcess('my-api')
if (api) {
console.log(`PID: ${api.pid}, Command: ${api.command}`)
}
// Remove a process record
removeProcessByName('old-service')Process Management
import { handleRun, isProcessRunning, terminateProcess } from 'bgr'
// Start a new managed process (same as `bgr --name ...` CLI)
await handleRun({
action: 'run',
name: 'my-api',
command: 'bun run server.ts',
directory: '/path/to/project',
force: true,
remoteName: '',
})
// Check if a process is alive
const alive = await isProcessRunning(12345)
// Stop a process
await terminateProcess(12345)Building a Custom Dashboard
The BGR dashboard itself is built using this API. Here's a minimal example of a custom process status endpoint:
// my-dashboard/api/status/route.ts
import { getAllProcesses, isProcessRunning, calculateRuntime } from 'bgr'
export async function GET() {
const procs = getAllProcesses()
const enriched = await Promise.all(
procs.map(async (p) => ({
name: p.name,
pid: p.pid,
running: await isProcessRunning(p.pid),
runtime: calculateRuntime(p.timestamp),
}))
)
return Response.json(enriched)
}Reading Process Logs
import { getProcess, readFileTail } from 'bgr'
const proc = getProcess('my-api')
if (proc) {
const stdout = await readFileTail(proc.stdout_path, 50) // last 50 lines
const stderr = await readFileTail(proc.stderr_path, 50)
console.log(stdout)
}Why BGR is Better than Alternatives
vs Simple Spawning
Simple spawning:
const child = Bun.spawn(["node", "script.js"]);Problems:
- No automatic restart if process crashes
- No port conflict resolution
- No environment variable management
- No log capture
- No process status tracking
BGR approach:
await Bun.$`bgr --name myapp --command "bun run script" --force`;- Auto-restart on crash via guard.ts
- Automatic port cleanup
- Config-based environment variables
- Structured logging
- Persistent process tracking
vs Workers
Workers limitations:
- Single memory space, isolation challenges
- Limited to Node.js/Bun environment
- Complex inter-process communication
- Resource management issues
BGR advantages:
- True process isolation
- Any executable or script
- Simple inter-process communication via file system
- Better resource management
- Cross-language compatibility
vs PM2/Process Managers
Traditional process managers:
- Heavy dependencies
- Complex configuration
- Node.js only
- Slower startup
- Complex API
BGR benefits:
- Built on Bun - ultra-fast startup
- Simple CLI and API
- Language agnostic
- Lightweight dependencies
- Native Bun features
Configuration
TOML Config Files
BGR automatically loads TOML configuration files and converts them to environment variables:
# .config.toml
[server]
port = 3000
host = "0.0.0.0"
timeout = 30000
[database]
url = "postgresql://localhost/myapp"
pool_size = 10
connection_timeout = 5000
[logging]
level = "info"
format = "json"Becomes environment variables:
SERVER_PORT=3000SERVER_HOST=0.0.0.0SERVER_TIMEOUT=30000DATABASE_URL=postgresql://localhost/myappDATABASE_POOL_SIZE=10DATABASE_CONNECTION_TIMEOUT=5000LOGGING_LEVEL=infoLOGGING_FORMAT=json
Environment Variables
# Custom database path
DB_NAME=myapp bgr
# Process grouping
BGR_GROUP=production bgr --name api-server --command "bun run server"File Structure
~/.bgr/
├── bgr.sqlite # Process database
├── myapp-out.txt # stdout logs
├── myapp-err.txt # stderr logs
└── backup/ # Historical logs
├── myapp-out-2024-01-01.txt
└── myapp-err-2024-01-01.txtGuard Process for Auto-Restart
For critical processes, use the guard script to automatically restart them if they stop:
# Monitor a process and restart it if it crashes
bun run guard.ts myapp 30
# Monitor every 30 seconds and auto-restartAdvanced Examples
Multi-Service Development
# Start all services
BGR_GROUP=dev bgr --name frontend --directory ./frontend --command "bun run dev --watch" --watch --force
BGR_GROUP=dev bgr --name backend --directory ./backend --command "bun run --watch server.ts" --watch --config .dev.toml
BGR_GROUP=dev bgr --name database --directory ./ --command "docker run -p 5432:5432 postgres:15"
# View all dev services
bgr --filter dev
# Restart specific service
bgr --restart backendProduction Architecture
# Start production services
bgr --name main-api --directory /var/api --command "bun run server" --config prod.toml --fetch --stdout /var/log/main-api.log --stderr /var/log/main-api.err
bgr --name cache-server --directory /var/cache --command "redis-server" --config redis.toml
bgr --name background-worker --directory /var/workers --command "bun run worker" --config worker.toml --force
# Monitor services
while true; do
bgr --json | jq '.[] | select(.status == "running") | .name'
sleep 60
doneDynamic Process Management
// orchestrator.ts
import {
handleRun,
getAllProcesses,
isProcessRunning,
terminateProcess,
} from 'bgr'
class ServiceOrchestrator {
async startService(name: string, command: string, directory: string) {
await handleRun({ action: 'run', name, command, directory, force: true, remoteName: '' })
}
async stopService(name: string) {
const proc = getAllProcesses().find(p => p.name === name)
if (proc && await isProcessRunning(proc.pid)) {
await terminateProcess(proc.pid)
}
}
async getHealthCheck() {
const procs = getAllProcesses()
const results = await Promise.all(
procs.map(async (p) => ({
name: p.name,
healthy: await isProcessRunning(p.pid),
}))
)
return results
}
}
// Usage
const orchestrator = new ServiceOrchestrator()
await orchestrator.startService('api', 'bun run server', './api')
console.log(await orchestrator.getHealthCheck())API Reference
Environment Variables
| Variable | Description | Default |
|----------|-------------|---------|
| DB_NAME | Custom database name | bgr |
| BGR_GROUP | Process grouping for filtering | - |
Command Options
| Option | Description | Default |
|--------|-------------|---------|
| --name <name> | Process name | Required |
| --directory <path> | Working directory | Required |
| --command <cmd> | Command to execute | Required |
| --config <path> | Config file path | .config.toml |
| --force | Force restart running process | false |
| --fetch | Pull latest git changes | false |
| --watch | Watch for file changes and auto-restart | false |
| --stdout <path> | Custom stdout log path | ~/.bgr/<name>-out.txt |
| --stderr <path> | Custom stderr log path | ~/.bgr/<name>-err.txt |
| --db <path> | Custom database path | ~/.bgr/bgr.sqlite |
| --json | Output in JSON format | false |
| --filter <group> | Filter by BGR_GROUP | - |
| --logs | Show process logs | false |
| --log-stdout | Show only stdout logs | false |
| --log-stderr | Show only stderr logs | false |
| --lines <number> | Number of log lines to show | All |
| --help | Show help | - |
| --version | Show version | - |
Testing
bun testLicense
MIT
