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.
- -file/-xfile - Include/exclude files.
- -dir/-xdir - Include/exclude directories.
- -cd - Change to a different directory to run the commands.
- -root - Specify additional root directories to watch.
- -exit - Exit when the last command exits.
- -stdin - Enable stdin for the last command.
- -verbose - Log file events.
- Chaining commands
- Clear terminal on restart
- Running parallel wgo commands
- Debug Go code using GoLand or VSCode with wgo
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 an alphabet [a-zA-Z]
is treated as a dot literal i.e. \.
So .css
really means \.css
, but .*
still means .*
because *
is not an alphabet. If you really want to use the dot .
wildcard followed by an alphabet, wrap it in (a bracket group) so that it is not immediately followed by an alphabet 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
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.
# Allow main.go to read from stdin.
$ wgo run -stdin main.go
# Only ./main (the last command) gets to read from stdin, `go build` does not get stdin.
$ wgo -stdin -file .go go build -o main main.go :: ./main
If the -verbose flag is provided, file events are logged.
Without -verbose:
$ wgo run ./server
Listening on localhost:8080
Listening on localhost:8080 # <-- file edited.
With -verbose:
$ wgo run -verbose ./server
[wgo] WATCH /Users/bokwoon/Documents/wgo/testdata
[wgo] WATCH args
[wgo] WATCH build_flags
[wgo] WATCH dir
[wgo] WATCH dir/foo
[wgo] WATCH dir/subdir
[wgo] WATCH dir/subdir/foo
[wgo] WATCH env
[wgo] WATCH file_event
[wgo] WATCH hello_world
[wgo] WATCH server
[wgo] WATCH signal
[wgo] WATCH stdin
Listening on localhost:8080
[wgo] CREATE server/main.go~
[wgo] CREATE server/main.go
[wgo] WRITE server/main.go
Listening on localhost:8080
You need to ensure the delve debugger is installed.
go install github.com/go-delve/delve/cmd/dlv@latest
$ wgo -file .go go build -o my_binary_name . :: sh -c 'while true; do dlv exec my_binary_name --headless --listen :2345 --api-version 2; done'
# If you're on Windows:
$ wgo -file .go go build -o my_binary_name.exe . :: pwsh.exe -command 'while (1) { dlv exec my_binary_name.exe --headless --listen :2345 --api-version 2 }'
You should see something like this
$ wgo -file .go go build -o my_binary_name . :: sh -c 'while true; do dlv exec my_binary_name --headless --listen :2345 --api-version 2; done'
API server listening at: [::]:2345
2024-12-01T01:18:13+08:00 warning layer=rpc Listening for remote connections (connections are not authenticated nor encrypted)
In the menu bar, Click on Run > Edit Configurations > Add New Configuration > Go Remote. Then fill in these values.
Name: Attach Debugger
Host: localhost
Port: 2345
On disconnect: Stop remote Delve process
Click OK. Now you can add breakpoints and then click Debug using this configuration. Make sure the Delve debugger server is first started!
{
"version": "0.2.0",
"configurations": [
{
"name": "Attach Debugger",
"type": "go",
"request": "attach",
"mode": "remote",
"host": "localhost",
"port": 2345
}
]
}
Save the launch.json file. Now you can add breakpoints and Start Debugging using this configuration. Make sure the Delve debugger server is first started!
Nothing! File watchers honestly all do the same things, if you find a file watcher that works for you there's no reason to change. Maybe wgo has a lower bar to entry? Or maybe you're allergic to unnecessary config files like I am. Or if you want a feature like chained commands or parallel commands, consider using wgo
.
I've been calling it wi-go or wuh-go inside my head.
See START_HERE.md.
https://github.com/bokwoon95/wgo/releases/latest/download/wgo-linux
curl --location --output wgo 'https://github.com/bokwoon95/wgo/releases/latest/download/wgo-linux'
https://github.com/bokwoon95/wgo/releases/latest/download/wgo-linux-arm
curl --location --output wgo "https://github.com/bokwoon95/wgo/releases/latest/download/wgo-linux-arm"
https://github.com/bokwoon95/wgo/releases/latest/download/wgo-macos
curl --location --output wgo "https://github.com/bokwoon95/wgo/releases/latest/download/wgo-macos"
https://github.com/bokwoon95/wgo/releases/latest/download/wgo-macos-apple-silicon
curl --location --output wgo "https://github.com/bokwoon95/wgo/releases/latest/download/wgo-macos-apple-silicon"
https://github.com/bokwoon95/wgo/releases/latest/download/wgo-windows.exe
curl --location --output wgo.exe "https://github.com/bokwoon95/wgo/releases/latest/download/wgo-windows.exe"