DEV Community

Cover image for I maintained deployment bash scripts for 10 years. Then I rewrote everything in Go.
Murry Jeong
Murry Jeong

Posted on

I maintained deployment bash scripts for 10 years. Then I rewrote everything in Go.

Every company I worked at had The Script.

You know the one. deploy.sh. 500 lines of bash. Written by someone who left 3 years ago. Nobody dares touch it, but everyone runs it in production every day.

At one company, it was server-manager — a 2,000-line monster managing 20+ services across Kafka clusters, Redis, MongoDB, Spring Boot microservices, and monitoring stacks. It worked. Until someone deployed a feature branch to production on a Friday evening. That's when we added branch checking. Then someone deployed two services simultaneously and half the servers got version A and the other half got version B. That's when we added deploy locking.

Every feature in the script existed because something had broken in production.

After 10 years and multiple companies, the pattern was always the same:

  1. Start with ssh server && git pull && restart
  2. Add packaging (tar.gz)
  3. Add rollback (symlinks)
  4. Add health checks (port/HTTP)
  5. Add config per environment
  6. Add parallel deployment
  7. End up with an unmaintainable bash monster

So I rewrote it. In Go.

The result: Tow

brew install neurosamAI/tap/tow

cd my-project
tow init                            # scans project, generates config
tow auto -e prod -m api-server     # build → deploy → health check
tow rollback -e prod               # symlink switch, <1 second
Enter fullscreen mode Exit fullscreen mode

Single binary. Zero dependencies on target servers. Just SSH.

What tow init does is the part I'm most proud of. It auto-detects your project — language, framework, build tool, monorepo modules — and generates a complete deployment config. 10 languages, 40+ frameworks. No more writing YAML from scratch.

The moment it clicked

I tested Tow on real production — 22 servers running Spring Boot, Kafka, Redis, MongoDB, Prometheus, Grafana. The same infrastructure that the old bash scripts managed.

$ tow doctor -e prod -m api-server
  ✓ tow.yaml is valid
  ✓ SSH connection successful
  ✓ Remote dir exists
  ✓ Disk space — Available: 4.9G
  ✓ No active deploy lock
  9 passed, 0 failed
Enter fullscreen mode Exit fullscreen mode

Then I checked the Kafka cluster:

$ tow logs -e prod -m kafka --all -n 3
[kafka-1] 2026-03-30 14:35:49 GC Pause Young 765M→702M 17ms
[kafka-2] 2026-03-30 14:35:55 GC Pause Young 340M→292M 18ms
[kafka-3] 2026-03-30 14:36:01 GC Pause Young 797M→723M 13ms
Enter fullscreen mode Exit fullscreen mode

Three servers, color-coded, one terminal. No tmux. No separate SSH sessions.

$ tow ssh -e prod -m kafka --all -- "free -h | head -2"
[kafka-1] Mem:  1.9Gi  1.7Gi  66Mi
[kafka-2] Mem:  1.9Gi  1.7Gi  77Mi
[kafka-3] Mem:  1.9Gi  1.7Gi  70Mi
Enter fullscreen mode Exit fullscreen mode

This was the moment I realized the 10 years of bash scripts were worth it — not because the scripts were good, but because every painful failure taught me what a deployment tool actually needs.

What I learned (the hard way)

Production incident Feature it became
Two devs deployed simultaneously → inconsistent state Deploy locking
Feature branch deployed to prod on Friday Branch policies
Deploy "succeeded" but app was crash-looping Health checks (HTTP, TCP, log, command)
Server 1 needed 4GB heap, server 2 needed 2GB Hierarchical config per server
Rollback took 15 minutes (rebuild + redeploy) Symlink switch (<1 second)
New dev spent 2 days writing deploy scripts tow init auto-detection

The part nobody else has

Tow has a built-in MCP server. That means Claude, Cursor, or Windsurf can deploy your code:

"Check prod status"tow status -e prod
"Show error logs from kafka"tow logs -e prod -m kafka -f ERROR
"Roll back the API"tow rollback -e prod -m api-server

No other deployment tool does this.

Why not just use...

Ansible? — I tried. Ended up with 2,000 lines of YAML playbooks that nobody fully understood. Tow is one config file.

Capistrano? — Great, but I run Spring Boot + Node.js + Python + Kafka + Redis. Not a Ruby shop.

Kamal? — Love the philosophy, but Docker on every server is a non-starter for JVM apps that already manage their own lifecycle.

Kubernetes? — For 5 servers? No.

Try it

brew install neurosamAI/tap/tow
# or: npm install -g @neurosamai/tow
# or: go install github.com/neurosamAI/tow-cli/cmd/tow@latest

cd your-project
tow init
# edit tow.yaml with your server IPs
tow auto -e dev -m your-app
Enter fullscreen mode Exit fullscreen mode

MIT License. 35 bundled infrastructure plugins. Open issues welcome.

If you've ever maintained The Script, you know why I built this.

Top comments (0)