๐ช๐ต๐ ๐ ๐ฅ๐ฒ๐ฝ๐น๐ฎ๐ฐ๐ฒ๐ฑ ๐ก๐ผ๐ฑ๐ฒ.๐ท๐ ๐๐ถ๐๐ต ๐ฏ๐ฌ ๐๐ถ๐ป๐ฒ๐ ๐ผ๐ณ ๐๐ฎ๐๐ต
I used to run a Node.js service to notify Google and Bing of URL changes.
The Node.js version worked. It also had forty dependencies. It required a runtime. It broke three weeks later because of a minor version update in a library.
For a task that runs once a day, that was too much maintenance.
I deleted it. I rewrote it in thirty lines of Bash using curl, openssl, and jq. It has run every night since without a single update.
Here is when this trade works.
Use Bash for narrow, stable, I/O-bound tasks. If you only need to call an API, parse small JSON, and log results, Bash is a great fit. No dependencies is a feature.
The benefits:
- No node_modules to audit.
- No runtime to patch.
- No lockfile drift.
- You can read the whole program on one screen.
- Failures show as clear HTTP status codes in logs.
But do not use Bash if your task grows.
The advantages flip the moment you need more complexity.
Avoid Bash if you need:
- State or complex logic: Handling things like quotas or retries turns Bash into messy code.
- Testing: Writing unit tests for a pile of curl calls is difficult.
- Team maintenance: Clever Bash scripts are hard for other engineers to read.
- Complex parsing: If you need to handle nested JSON or HTML, stop. Bash string handling is not enough.
The choice is not Bash versus Node.js. The choice is about how much your requirements will change.
A script that does one stable thing on a timer is perfect for Bash. The moment you need state, tests, or teammates, you should switch back to a real programming language.
I keep my Bash script because it stays small. I chose it knowing it would stay simple.
Use boring, dependency-free tools only as long as the task stays boring. The skill is knowing when to stop.