Stop writing CLI validation. Parse it right the first time

https://news.ycombinator.com/rss Hits: 17
Summary

I have this bad habit. When something annoys me enough times, I end up building a library for it. This time, it was CLI validation code. See, I spend a lot of time reading other people's code. Open source projects, work stuff, random GitHub repos I stumble upon at 2 AM. And I kept noticing this thing: every CLI tool has the same ugly validation code tucked away somewhere. You know the kind: if (!opts.server && opts.port) { throw new Error("--port requires --server flag"); } if (opts.server && !opts.port) { opts.port = 3000; // default port } // wait, what if they pass --port without a value? // what if the port is out of range? // what if... It's not even that this code is hard to write. It's that it's everywhere. Every project. Every CLI tool. The same patterns, slightly different flavors. Options that depend on other options. Flags that can't be used together. Arguments that only make sense in certain modes. And here's what really got me: we solved this problem years ago for other types of data. Just… not for CLIs. The problem with validation There's this blog post that completely changed how I think about parsing. It's called Parse, don't validate by Alexis King. The gist? Don't parse data into a loose type and then check if it's valid. Parse it directly into a type that can only be valid. Think about it. When you get JSON from an API, you don't just parse it as any and then write a bunch of if-statements. You use something like Zod to parse it directly into the shape you want. Invalid data? The parser rejects it. Done. But with CLIs? We parse arguments into some bag of properties and then spend the next 100 lines checking if that bag makes sense. It's backwards. So yeah, I built Optique. Not because the world desperately needed another CLI parser (it didn't), but because I was tired of seeing—and writing—the same validation code everywhere. Three patterns I was sick of validating Dependent options This one's everywhere. You have an option that only makes sense w...

First seen: 2025-09-06 21:27

Last seen: 2025-09-07 13:40