We need to talk about the "Micro-Interruption" and what it actually does to your brain during an intense coding session.
You know the specific feeling I am talking about:
- You are deep in the code mines, mentally holding a complex dependency graph in your head, and you finally implement the fix for a race condition.
- You hit Cmd+S to save, and then the administrative ritual begins.
- You have to physically shift your focus from your code editor to your terminal window, breaking your visual focus.
- You have to press Ctrl+C to send a kill signal to your running server and wait a split second for the socket to close.
- You press the Up Arrow to recall your run command, and finally, you hit Enter.
It seems like a trivial action that takes only a few seconds, but when you perform it hundreds of times a day, the cumulative effect is devastating.
It is not just the time lost; it is the destruction of your "Flow State"
Every single time you interact with the terminal to do administrative work, your brain drops a tiny piece of the complex logic you were holding.
By the time the server/app restarts and you look back at your code, you have to spend mental energy "reloading" your own internal state, slowing down your momentum significantly.
Make the tooling invisible
To improve my daily development workflow, I built watch cause I was exhausted from fighting my terminal and wanted a "save and see" experience that felt native to the Go ecosystem.
It is a zero-dependency, zero-configuration CLI tool that handles the restart cycle for you automatically, effectively removing the barrier between writing code and seeing the results of that code. It respects the Go philosophy of simplicity: a single binary that does one thing well.
Unlike polling-based watchers that eat your battery with polling, it uses native OS filesystem events to react instantly with fswatcher, another low-level library that I recently published.
Zero Config, instant feedback
The beauty of the tool lies in its absolute simplicity and lack of friction. If your standard workflow involves running your application with go run ., you do not need to change your project structure, add a config file, or learn a new set of flags.
Prefix your command with watch, and instead of the manual cycle of stopping and starting, you transition to a "fire and forget" mode.
That is the extent of the onboarding process. From that moment on, watch takes over the tedious process management loop. It monitors your .go files, your go.mod, and your go.sum recursively with intelligent defaults, automatically ignoring hidden directories like .git or vendor folders.
Here is what the immediate transition looks like in your daily workflow:
# ❌ The Old Way (The "Muscle Memory" Trap)
# 1. Run the app
$ go run cmd/server/main.go
# 2. Switch to editor, make changes, save
# 3. Switch to terminal
# 4. Hit CTRL+C to kill the process
# 5. Hit Up Arrow, then Enter to restart
# 6. Repeat 100x a day
# ✅ The New Way (The "Flow State" Method)
# 1. Run this once in the morning
$ watch go run cmd/server/main.go
# 2. Never touch the terminal again
If you are doing Test Driven Development, you can have watch re-run your test suite every time you save a file, giving you immediate red/green feedback without lifting a finger.
# The standard way (boring and manual):
$ go test -v ./...
# The TDD way (instant and automated):
$ watch go test -v ./...
Using the CLI mode, we can construct a "one-liner" more advanced that acts as a complete development environment. There is support for command chaining, environment injection, and regex filtering all at once.
watch \
--path="./services/billing" \
--regex=".*\\.go$" \
--env="PORT=8081,DB_HOST=localhost,DB_USER=postgres" \
--cmd "go fmt ./services/billing/..." \
--cmd "go vet ./services/billing/..." \
--cmd "go run ./services/billing/cmd/server"
Advanced workflow
The CLI is powerful, but typing that command every day is tedious, and sharing it with a team is difficult. For complex, reproducible workflows, there is support for a customizable watch YAML file.
Let's imagine a scenario where you are building a Go web application that serves HTML templates. You have a split requirement:
- Backend Code (.go): Needs to trigger a recompile and restart.
- Frontend Templates (.html): Should also restart the server (to reload templates), but you don't need to run Go linters on HTML files.
- Test Files (_test.go): Should never restart the server. Instead, they should run the test suite in parallel with the server to ensure you haven't broken anything.
config:
path: .
logLevel: info
jobs:
# Triggers on Go files
backend-dev:
on:
regex:
- ".*\\.go$"
- "!.*_test.go$" # Explicitly exclude tests
series:
- cmd: "golangci-lint run"
- cmd: "go build -o ./tmp/app ."
- cmd: "./tmp/app"
# Template Reloader
frontend-reload:
on:
regex:
- ".*\\.html$"
series:
- cmd: "./tmp/app"
# Parallel test runner
test-runner:
on:
regex:
- ".*_test\\.go$"
parallel:
- cmd: "go test -v ./..."
- cmd: "govulncheck ./..."
Whether you are running a quick one-off script with the CLI or orchestrating a complex microservices architecture with a watch.yml, the goal remains the same: remove the friction between your thought process and the running code.
Top comments (0)