Scaffold CLI

Scaffold CLI

Command-line generator that scaffolds fully wired feature modules for our internal Next.js starter, with tests and stories included.

Node.jsTypeScriptCommander.jsHandlebarsVitest
View liveView repo

The problem

Every new feature on our team started with the same 20 minutes of copy-pasting a route, a component, a test file, and a Storybook story from an existing feature, then renaming everything by hand. I wanted a CLI that generated all of it correctly in one command.

Role and impact

Technical decisions and challenges

Hardcoded string templates drift out of sync the moment the starter's conventions change, since nobody remembers to update the generator alongside the code. I compared maintaining static template strings versus generating templates directly from an existing "reference" feature module in the repo.

I chose to generate templates from a living reference module with placeholder tokens, because it means updating the starter's conventions once, in real code, automatically keeps the generator correct instead of relying on someone remembering to update a separate template file.

A generator that blindly overwrites files is dangerous the moment someone reruns it against a folder they've already started editing. I evaluated always overwriting with a warning versus a dry-run diff preview before any write.

I ended up requiring a dry-run diff preview by default, with an explicit --write flag to apply changes, since silent overwrites were the single scariest failure mode for a tool meant to save time, not create incidents.

Detailed stack

LayerTechnologyWhy
CLINode.js, Commander.jsSimple, well-documented command parsing and subcommands
TemplatingHandlebarsReadable templates with helpers for casing and pluralization
TestingVitestSnapshot tests over generated output for every template
Terminal output showing generated files for a new featureDry-run diff preview before writing files

What I would do differently

I would add an interactive prompt mode for picking which pieces to generate (route, tests, stories) instead of always generating the full set. Right now, a feature that doesn't need a Storybook story still gets one, which someone then has to remember to delete.