You can download binaries from the release page, or use the Go command:
go install github.com/bokwoon95/wgo@latest
If you are on macOS, you may install it with Homebrew.
brew install wgo
Usage:
wgo [FLAGS] <command> [ARGUMENTS...]
wgo gcc -o main main.c
wgo go build -o main main.go
wgo -file .c gcc -o main main.c
wgo -file=.go go build -o main main.go
wgo run [FLAGS] [GO_BUILD_FLAGS] <package> [ARGUMENTS...]
wgo run main.go
wgo run -file .html main.go arg1 arg2 arg3
wgo run -file .html . arg1 arg2 arg3
wgo run -file=.css -file=.js -tags=fts5 ./cmd/my_project arg1 arg2 arg3
Pass in the -h flag to the wgo/wgo run to learn what flags there are i.e. wgo -h, wgo run -h
Core documentation resides at https://github.com/bokwoon95/wgo#quickstart
Too many file watchers either force you to wrap your commands into strings, require config files or log tons of noisy output to your stdout. In contrast, wgo is dead simple and silent by default. The implementation is also really short, most of it resides in just two files (wgo_cmd.go and main.go). You can read the entire codebase in one sitting, start here.
It can be used like go run.
You already know how to use wgo. Simply slap wgo in front of any command in order to have it rerun whenever a file changes.
# Run gcc.
$ gcc -Wall -o main main.c
# Run gcc whenever a file changes.
$ wgo gcc -Wall -o main main.c
wgo run behaves exactly like go run except it runs again the moment any Go file changes. This can be used to live-reload Go servers. wgo run accepts the same flags as go run.
By default wgo run only watches .go files. To include additional file types such as .html, use the -file flag.
# Run main.go.
$ go run main.go
# Run main.go whenever a .go file changes.
$ wgo run main.go
# Any flag that can be passed to `go run` can also be passed to `wgo run`.
$ wgo run -tags=fts5 -race -trimpath main.go
wgo/wgo run take in additional flags. These flags must be passed in directly after wgo/wgo run, before invoking your command.
To include specific files eligible for triggering a reload, use the -file flag. It takes in a regex, and files whose paths (relative to the root directory) match the regex are included. You can provide multiple -file flags.
Path separators are always forward slash, even on Windows.
If no -file flag is provided, every file is included by default unless it is explicitly excluded by the -xfile flag.
# Run sass whenever an .scss file changes.
$ wgo -file .scss sass assets/styles.scss assets/styles.css
# Run main.go whenever a .go or .html or .css file changes.
$ wgo run -file .html -file .css main.go
# Run main.go when foo/bar/baz.go changes.
$ wgo run -file '^foo/bar/baz.go$' main.go
To exclude specific files, use the -xfile flag. It takes in a regex (like -file) but if it matches with a file path that file is excluded.
The -xfile flag takes higher precedence than the -file flag so you can include a large group of files using a -file flag and surgically ignore specific files from that group using an -xfile flag.
# `go test` writes to coverage.out, which counts as a changed file which triggers
# `go test` to run again which generates coverage.out again in an infinite loop.
# Avoid this by excluding any file matching 'coverage.out'.
$ wgo -xfile coverage.out go test . -race -coverprofile=coverage.out
# Probably better to specify `-file .go` in order to rerun `go test` only when
# .go files change.
$ wgo -file .go go test . -race -coverprofile=coverage.out
The -file flag takes in regexes like .html or .css.
$ wgo run -file .html -file .css main.go
Technically the dot . matches any character, but file extensions are such a common pattern that wgo includes a slight modification to the regex matching rules:
Any dot . immediately followed by a letter [a-zA-Z] is treated as a dot literal i.e. \.
So .css really means \.css, but .* still means .* because * is not a letter. If you really want to use the dot . wildcard followed by a letter, wrap it in (a bracket group) so that it is not immediately followed by a letter i.e. (.)abc.
To only watch specific directories, use the -dir flag. It takes in a regex, and directories whose paths (relative to the root directory) match the regex are included. You can provide multiple -dir flags.
Path separators are always forward slash, even on Windows.
# Run sass whenever an .scss file in the assets directory changes.
$ wgo -dir assets -file .scss sass assets/styles.scss assets/styles.css
# Run main.go whenever something in the foo directory or bar/baz directory changes.
$ wgo run -dir foo -dir bar/baz main.go
# Run main.go whenever something in the foo/bar/baz directory changes.
$ wgo run -dir '^foo/bar/baz$' main.go
To exclude specific directories, use the -xdir flag. It takes in a regex (like -dir) but if it matches with a directory path that directory is excluded from being watched.
# Run main.go whenever a file changes, ignoring any directory called node_modules.
$ wgo run -xdir node_modules main.go
In practice you don't have to exclude node_modules because it's already excluded by default (together with .git, .hg, .svn, .idea, .vscode and .settings). If you do want to watch any of those directories, you should explicitly include it with the -dir flag.
Commands can be chained using the :: separator. Subsequent commands are executed only when the previous command succeeds.
# Run `make build` followed by `make run` whenever a file changes.
$ wgo make build :: make run
# Run `go build` followed by the built binary whenever a .go file changes.
$ wgo -file .go go build -o main main.go :: ./main
# Clear the screen with `clear` before running `go test`.
# Windows users should use `cls` instead of `clear`.
$ wgo -file .go clear :: go test . -race -coverprofile=coverage.out
Since :: designates the command separator, if you actually need to pass in a :: string an an argument to a command you should escape it by appending an extra : to it. So :: is escaped to :::, ::: is escaped to ::::, and so on.
Chained commands execute in their own independent environment and are not implicitly wrapped in a shell. This can be a problem if you want to use shell specific commands like if-else statements or if you want to pass data between commands. In this case you should explicitly wrap the command(s) in a shell using the form sh -c '<command>' (or pwsh.exe -command '<command>' if you're on Windows).
# bash: echo "passed" or "failed" depending on whether the program succeeds.
$ wgo -file .go go build -o main main.go :: bash -c 'if ./main; then echo "passed"; else echo "failed"; fi'
# powershell: echo "passed" or "failed" depending on whether the program succeeds.
$ wgo -file .go go build -o main main.go :: pwsh.exe -command './main; if ($LastExitCode -eq 0) { echo "passed" } else { echo "failed" }'
You can chain the clear command (or the cls command if you're on Windows) so that the terminal is cleared before everything restarts. You will not be able to use the wgo run command, instead you'll have to use the wgo command as a general-purpose file watcher to rerun go run main.go when a .go file changes.
# Clears the screen.
$ clear
# When a .go file changes, clear the screen and run go run main.go.
$ wgo -file .go clear :: go run main.go
# If you're on Windows:
$ wgo -file .go cls :: go run main.go
If a command separator :: is followed by wgo, a new wgo command is started (which runs in parallel).
# Run the echo commands sequentially.
$ wgo echo foo :: echo bar :: echo baz
# Run the echo commands in parallel.
$ wgo echo foo :: wgo echo bar :: wgo echo baz
This allows you to reload a server when .go files change, but also do things like rebuild .scss and .ts files whenever they change at the same time.
$ wgo run main.go \
:: wgo -file .scss sass assets/styles.scss assets/styles.css \
:: wgo -file .ts tsc 'assets/*.ts' --outfile assets/index.js
Even if wgo was invoked with go tool wgo or its full binary path (e.g. /usr/local/bin/wgo), wgo only recognizes the magic string "wgo" after the "::" as the signal to start a new parallel command (otherwise it is treated as a chained command).
# ❌ These do not start parallel wgo commands. Do not nest wgo commands like this.
$ go tool wgo echo 1 :: go tool wgo echo 2 :: go tool wgo echo 3
$ /usr/local/bin/wgo echo 1 :: /usr/local/bin/wgo echo 2 :: /usr/local/bin/wgo echo 3
# ✅ These start parallel wgo commands.
$ wgo echo 1 :: wgo echo 2 :: wgo echo 3
$ go tool wgo echo 1 :: wgo echo 2 :: wgo echo 3
$ /usr/local/bin/wgo echo 1 :: wgo echo 2 :: wgo echo 3
# └┬┘ └┬┘
# └──────┬──────┘
# This is not spawning a separate wgo process, it is a placeholder string
# recognized by the wgo binary, which is in turn responsible for running all the
# specified commands in parallel. There is only ever one parent wgo process.
If you want to run commands in a different directory from where wgo was invoked, used the -cd flag.
# Run main.go whenever a file changes.
$ wgo run main.go
# Run main.go from the 'app' directory whenever a file changes.
$ wgo run -cd app main.go
By default, the root being watched is the current directory. You can watch additional roots with the -root flag. Note that the -file/-xfile and -dir/-xdir filters apply equally across all roots.
# Run main.go whenever a file in the current directory or the parent directory changes.
$ wgo run -root .. main.go
# Run main.go whenever a file in the current directory or the /env_secrets directory changes.
$ wgo run -root /env_secrets main.go
You may also be interested in the -cd flag, which lets you watch a directory but run commands from a different directory.
If the -exit flag is provided, wgo exits once the last command exits. This is useful if your program is something like a server which should block forever, so file changes can trigger a reload as usual but if the server ever dies on its own (e.g. a panic or log.Fatal) wgo should exit to signal to some supervisor process that the server has been terminated.
# Exit once main.go exits.
$ wgo run -exit main.go
# Exit once ./main exits.
$ wgo -exit -file .go go build -o main main.go :: ./main
By default, stdin to wgo is ignored. You can enable it for the last command using the -stdin flag. This is useful for reloading programs that read from stdin.
```shell