Skip to content

rw3iss/gow

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

35 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

gow

A small, fast, cross-platform file watcher + rebuilder + runner for Go projects.

  • Zero-config default. Runs on any Go module with gow — watches the tree, builds with go build, runs the output binary, restarts on change.
  • Sensible filtering. Only .go files trigger rebuilds by default. Deny-list covers .git, node_modules, dist, bin, .idea, .vscode automatically.
  • Debounced. Rapid bursts of writes (atomic-save editors, gofmt) coalesce into one rebuild.
  • Clean shutdown. Ctrl+C interrupts the target process group before exiting — no orphaned children.
  • Cross-platform. Uses fsnotify; Unix signal group handling via build tags.

Alt text

Install

go install github.com/rw3iss/gow@latest

Or from source:

git clone https://github.com/rw3iss/gow.git
cd gow
go install

Quick start

From any Go module directory:

gow

This watches ./**/*.go, runs go build, then runs ./<modulename>. Restarts on every relevant change.

Common overrides

# Run via `go run` instead of the built binary.
gow -run "run main.go"

# Watch a subdirectory and run a pre-built binary elsewhere.
gow -dir ./server/api -run "./bin/api"

# Pass extra build flags.
gow -build "build -race -tags dev"

# Verbose mode — logs every filesystem event and debounce decision.
gow -debug

CLI flags

Flag Default Purpose
-config <path> auto (./config.json if any) Path to optional config.json
-dir <path> current working directory Directory to watch + build in
-run <cmd> ./<workdir-basename> Run command. Starts with ./ or / → exec directly. Otherwise treated as go <args>.
-build <cmd> build go <cmd> to invoke for builds
-debug off Verbose logging
-v, -version Print version
-h, -help Help

Optional config.json

Config is fully optional. Place a config.json in the working directory (or point at one with -config) to override any default. All keys are optional:

{
  "watchDir": "./",
  "buildCommand": "build",
  "runCommand": "./myapp",
  "extensions": [".go", ".tmpl"],
  "denyFragments": [".git", "node_modules", "dist"],
  "debounceMs": 200
}
Key Type Default
watchDir string workdir
buildCommand string "build" — passed to go as subcommand + args
runCommand string "./<workdir-basename>" — exec'd directly if it starts with ./ or /, else passed to go
extensions []string [".go"] — allow-list of extensions that trigger rebuild
denyFragments []string [".git", "node_modules", "dist", "bin", ".idea", ".vscode", ".cache", ".swp", "~"]
debounceMs int 200 — coalesce bursts of events into one rebuild

CLI flags always win over config; config always wins over defaults.

Project layout

main.go                  Entry point. Parses flags, wires Application.
lib/
  Application.go         Central bus. Owns lifecycle + signal handling.
  Builder.go             Wraps `go build`. Returns exec errors cleanly.
  Runner.go              Owns the child process. Smart exec (./bin vs go).
  Watcher.go             fsnotify wrapper with filter + debounce.
  proc_unix.go           Process-group setup for clean teardown (Unix).
  proc_windows.go        No-op stub (Windows lacks POSIX process groups).
  utils/
    Colors.go            ANSI color constants.
    Config.go            JSON config loader. Missing file is benign.
    Convert.go           Array-of-interface → []string helper.
    FormatWriter.go      io.Writer wrapper that prefixes output.
    Log.go               Log / Debug / LogError.
test/
  test.go                Trivial target for manually smoke-testing gow.

Troubleshooting

  • Ctrl+C leaves a child process running. Shouldn't happen since 2026-04 — if you still see it, run with -debug to see the teardown sequence and file an issue. Known limitation: Windows doesn't have POSIX process groups so a grandchild that ignores taskkill may outlive gow.
  • Rebuild fires on my editor's swap file. Add the swap suffix to denyFragments, or extend extensions to be stricter.
  • My rebuild runs twice per save. Your editor is writing the file multiple times. The default 200ms debounce should catch most of this — increase debounceMs if not.

Consuming as a library

The lib/ packages are public and usable from other Go code:

import "github.com/rw3iss/gow/lib"

app := lib.NewApplication(lib.Options{
    WorkDir:      "/path/to/project",
    RunCommand:   "run main.go",
    DebugEnabled: true,
})
app.Init() // blocks until signal

Useful for embedding a live-reload loop in a larger tool (test harnesses, IDE integrations).

About

Go file watcher, builder, and runner. Barebones (fast), cross-platform (uses fsnotify), recursive, and configurable.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages