A blazingly fast, production-ready hot reload engine for Go projects — with health checks, crash loop protection, a real-time dashboard, and more. No Air. No Realize. No hidden magic.
| Feature | Description | |
|---|---|---|
| ✅ | Sub-2-Second Reloads | Optimized rebuild and restart pipeline |
| ✅ | Intelligent Debouncing | Handles editor save bursts gracefully (default 300ms) |
| ✅ | Nested Directory Support | Watches the entire project tree recursively |
| ✅ | Graceful Process Management | Clean shutdown with SIGTERM → SIGKILL escalation |
| ✅ | Real-Time Log Streaming | See build and server logs instantly — zero buffering |
| ✅ | Crash Loop Protection | Exponential backoff prevents restart storms |
| Feature | Description | |
|---|---|---|
| 🌐 | Web Dashboard | Real-time build status at http://localhost:3000 |
| 🏥 | HTTP Health Checks | Verify the server actually started before marking OK |
| 🔔 | Desktop Notifications | Cross-platform alerts on build success/failure |
| 🧠 | Build Fingerprinting | Skip rebuilds when only timestamps change |
| 📋 | YAML Configuration | .hotreload.yaml — no more long CLI commands |
| 🎨 | Beautiful Terminal Output | Color-coded, structured slog component logs |
| 🔍 | Smart Filtering | .gitignore integration + custom glob patterns |
# Clone and build
git clone https://github.com/Shiva210Jyoti/hot-reload-engine
cd hot-reload-engine
go build -o ./bin/hotreload ./cmd/hotreloadOr install directly:
go install github.com/Shiva210Jyoti/hot-reload-engine/cmd/hotreload@latesthotreload \
--root ./myproject \
--build "go build -o ./bin/server ./cmd/server" \
--exec "./bin/server"Create .hotreload.yaml in your project root:
root: ./myproject
build: go build -o ./bin/server ./cmd/server
exec: ./bin/server
debounce: 300ms
ignore_patterns:
- "**/*_test.go"
- "**/vendor/**"
health_check:
enabled: true
url: http://localhost:8080/health
timeout: 5s
interval: 500ms
max_retries: 10
notifications:
enabled: true
dashboard:
enabled: true
port: 3000Then simply run:
hotreloadmake demo
# or
./bin/hotreload --root ./testserver \
--build "go build -o ./bin/testserver ./testserver" \
--exec "./bin/testserver"In another terminal:
curl http://localhost:8080/ # → Server running - version 1.0.0
curl http://localhost:8080/health # → {"status":"ok", ...}
# Edit testserver/handler.go → save → watch auto-rebuild happen in < 2 seconds!flowchart TD
FS["📁 File System\n(fsnotify)"]
subgraph Coordinator["🎯 Coordinator — Event Orchestrator"]
direction TB
W["🔍 Watcher\nRecursive fsnotify\n+ Smart Filter"]
DB["⏱ Debouncer\n300ms collapse"]
FP["🧠 Fingerprinter\nSHA256 skip-opt"]
B["🔨 Builder\nexec + cancel"]
HC["🏥 HealthChecker\nHTTP poll"]
R["▶ Runner\nProcess manager\nSIGTERM→SIGKILL"]
CT["🛡 CrashTracker\nExp. backoff"]
N["🔔 Notifier\nDesktop alerts"]
DASH["🌐 Dashboard\nWebSocket UI"]
end
FS -->|"OS events"| W
W -->|"FileEvent"| DB
DB -->|"one signal"| FP
FP -->|"changed?"| B
B -->|"success"| R
B -->|"failure"| N
R -->|"started"| HC
R -->|"crash"| CT
CT -->|"backoff"| R
HC -->|"healthy"| N
B -->|"events"| DASH
R -->|"events"| DASH
See docs/ARCHITECTURE.md for a deep dive into every design decision.
hot-reload-engine/
├── cmd/hotreload/ # CLI entry point — flag parsing → Coordinator
├── internal/
│ ├── config/ # Config struct, YAML loader, defaults, validation
│ ├── debouncer/ # Thread-safe time-based event debouncer
│ ├── watcher/ # Recursive fsnotify wrapper + smart filter
│ ├── builder/ # Build command executor with context cancellation
│ │ └── fingerprint.go # SHA256 content hashing to skip redundant builds
│ ├── runner/ # Child process manager
│ │ ├── crashloop.go # Exponential backoff crash detector
│ │ ├── process_unix.go # SIGTERM → SIGKILL to process group
│ │ └── process_windows.go # taskkill /F /T /PID
│ ├── coordinator/ # Central event orchestrator
│ ├── dashboard/ # WebSocket HTTP server + embedded HTML UI
│ ├── healthcheck/ # HTTP health probe with retry logic
│ ├── logger/ # Custom slog handler with component labels
│ └── notifications/ # Cross-platform desktop notification (beeep)
├── testserver/ # Sample HTTP server for demonstration
│ ├── main.go # Server bootstrap + graceful shutdown
│ └── handler.go # /, /health, /crash endpoints
├── docs/
│ ├── ARCHITECTURE.md # Deep-dive design patterns
│ ├── CONFIGURATION.md # Complete config file reference
│ └── TROUBLESHOOTING.md # Common issues and solutions
├── .hotreload.yaml # Example config for the testserver
├── Makefile
├── go.mod
└── README.md
hotreload [flags]
Required (or set via .hotreload.yaml):
--root string Project root directory to watch
--build string Build command e.g. "go build -o ./bin/app ."
--exec string Execute command e.g. "./bin/app"
Optional:
--debounce duration Quiet period before rebuild (default 300ms)
--ext string Comma-separated extensions to watch (default ".go")
--exclude string Comma-separated extra glob patterns to exclude
--notifications Enable desktop notifications (default true)
--dashboard Enable web dashboard on :3000
--dashboard-port int Dashboard port (default 3000)
--version Print version and exit
| Variable | Effect |
|---|---|
HOTRELOAD_LOG_LEVEL |
Set log level: DEBUG, INFO (default), WARN, ERROR |
| Metric | Value |
|---|---|
| Typical rebuild time | < 2 seconds |
| Baseline memory usage | < 50 MB |
| Max watched files | 10,000+ |
| CPU overhead (idle) | < 1% |
BenchmarkDebouncer-8 1000000 1043 ns/op
BenchmarkFingerprinter-8 5000 245631 ns/op
BenchmarkWatcher-8 10000 112458 ns/op
Run yourself:
go test -bench=. -benchmem ./...# Run all tests
go test -v ./...
# Run with race detector
go test -v -race ./...
# Generate coverage report
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out -o coverage.html
# View function-level summary
go tool cover -func=coverage.outCurrent coverage: ~85%
| Package | Scenarios |
|---|---|
debouncer |
Single trigger, rapid collapse → 1 call, spaced triggers, Stop, Benchmark |
watcher |
Single file, nested dirs, runtime-created dirs, deletions, ignore globs, shutdown, symlinks, Benchmark |
filter |
.gitignore patterns, custom globs, defaults, table-driven edge cases |
builder |
Success, failure, context cancel, real-time log streaming |
fingerprint |
Same content, changed content, new file, non-Go files, Benchmark |
runner |
Start/Stop, graceful/force shutdown, restart sequence, log streaming |
crashloop |
Single backoff, exponential levels, reset |
config |
File loading, CLI override, defaults, invalid YAML |
coordinator |
Full E2E: build → binary → file change → rebuild → shutdown |
Editors often trigger multiple filesystem events per save. Without debouncing you'd get 5–10 redundant builds per keystroke. The 300ms default is tuned for typical editor behavior.
git checkout, go mod tidy, and many SCM operations change file modification times without touching content. SHA256 fingerprinting ensures rebuilds only happen from real changes.
A typical Go server spawns goroutines that open sockets and databases. On Unix, setting Setpgid: true lets us kill the entire process tree with a single kill(-pgid). Windows uses taskkill /F /T.
Process started ≠ server ready. A port might not be bound for 300ms after launch. Health checks poll a configured URL and only mark the server as ready after it responds with 2xx.
Rapid crash-restart loops burn CPU, make debugging harder, and are hard on OS process tables. Backoff starts at 1s and doubles (capped at 32s) — giving you time to fix the root cause.
HTTP polling creates unnecessary overhead and adds latency. A single persistent WebSocket connection lets the server push events (build start, log lines, file changes) at zero overhead.
make build # Build the hotreload binary → ./bin/hotreload
make demo # Watch the testserver with auto-reload
make test # Run the full test suite
make bench # Run benchmark suite
make clean # Remove build artifacts- ARCHITECTURE.md — Deep-dive into component design patterns
- CONFIGURATION.md — Complete
.hotreload.yamlreference - TROUBLESHOOTING.md — Common issues and solutions
MIT License — see LICENSE
Built with ❤️ for the Go developer community