Loading...
Loading...
I built a small CLI utility in Go for the first time. These are the things I did not expect.
I have been writing JavaScript and TypeScript for most of my career. Go has been on my list for a while, and earlier this year I finally had a reason to use it: I wanted to build a small CLI tool that watches a directory and syncs files to a remote server over SSH.
Here is what I learned.
Compiling to a single static binary is the main reason Go is popular for CLI tools, and it lives up to the reputation. Once I built the binary, I could copy it to any Linux machine and it just ran. No runtime, no dependency install step, no version conflicts.
The standard library covers a lot. SSH client support, file system watching, argument parsing, JSON handling. I did not need many third-party packages, and the ones I used were small and focused.
I needed two goroutines: one to watch the file system, one to handle the SSH connection and upload queue. Coordinating them with channels felt unfamiliar coming from async/await in JavaScript.
The mental model is different. In JavaScript, you are mostly thinking about a single-threaded event loop. In Go, your goroutines are actually running concurrently, and you have to think about shared state explicitly. I hit a data race on my first attempt because I was writing to a map from two goroutines without a mutex.
The race detector (go test -race) caught it immediately. That tool is very good.
You will write if err != nil a lot. Coming from JavaScript where you throw and catch, it felt tedious. But I started to appreciate it after debugging a few issues. Every function that can fail tells you exactly where it failed, because each error check is explicit.
I stopped fighting the pattern about halfway through the project. It is just how Go works, and the explicitness has real value in a tool where you want clear error messages for the user.
For long-running server processes and CLI tools, Go feels well-matched. The output is fast, the binary distribution story is clean, and the standard library saves you from pulling in a lot of dependencies.
I would not switch my web frontend to Go. But for system tools, small utilities, and services where you want low overhead and easy deployment, it made sense.