Boilerplate to Generators
How custom generators transformed our development workflow from inconsistent snowflakes to standardized, scalable patterns.
Boilerplate to Generators
The Redux Reality Check
Several years ago, when Redux was the shiny new solution for React state management, I was tasked with introducing it to our team. On paper, it looked perfect—predictable state updates, time-travel debugging, and a clear data flow pattern. In practice? The learning curve was steeper than expected, and the boilerplate requirements were... substantial.
But the real problem wasn't Redux itself. It was what happened when multiple developers started implementing Redux patterns across our codebase.
The Snowflake Problem
You know the scenario: one developer creates a Redux action that looks like this:
// Developer A's approach
const FETCH_USERS = 'FETCH_USERS';
const FETCH_USERS_SUCCESS = 'FETCH_USERS_SUCCESS';
const FETCH_USERS_ERROR = 'FETCH_USERS_ERROR';
While another developer, working on a similar feature, structures it differently:
// Developer B's approach
const GET_PRODUCTS_REQUEST = 'GET_PRODUCTS_REQUEST';
const GET_PRODUCTS_FULFILLED = 'GET_PRODUCTS_FULFILLED';
const GET_PRODUCTS_REJECTED = 'GET_PRODUCTS_REJECTED';
Neither approach is wrong, but now we have inconsistency. Multiply this across actions, reducers, selectors, and component connections, and soon you have a codebase full of beautiful, unique snowflakes—each one different, each one requiring mental overhead to understand.
The core problems we faced were:
- Inconsistent naming conventions across actions, reducers, and selectors
- Structural variations in how files were organized and imports handled
- Missing test coverage because writing Redux tests felt like extra work
- No clear "right way" documented anywhere in our codebase
- Time sink for simple features that required extensive boilerplate setup
After watching developers spend 15+ minutes setting up what should have been a 2-minute task, I knew we needed a different approach.
The Generator Evolution
Phase 1: Yeoman-Based Solution
My first attempt at solving this was generator-react-up, built on Yeoman. It automated the creation of Redux actions, reducers, and connected components with consistent patterns.
yo react-up:redux-feature UserManagement
This would scaffold out a complete Redux feature with standardized naming, proper file structure, and basic tests. The time savings were immediate, and more importantly, the consistency was guaranteed.
Phase 2: Framework-Agnostic Generator
The Yeoman dependency felt heavy for what we needed, so I created a standalone generator that could work with any project structure. This gave us more flexibility and faster execution.
Phase 3: NX Monorepo Integration
Fast forward to today. We're using NX monorepos, and NX's built-in generator system has become the foundation of our development workflow. The power of custom generators in a monorepo environment is transformative.
The NX Generator Advantage
With NX generators, we've built a comprehensive toolkit that addresses every aspect of our development process:
Smart Scaffolding with Validation
Our generators don't just create files—they ensure consistency through intelligent prompts and validation:
nx generate @mycompany/generators:react-component
The generator prompts for:
- Component type (presentational, container, form, etc.)
- Destination (with autocomplete for existing apps/libs)
- Name (with validation for naming conventions)
- Additional info (prompt for any additional info we'd like to parameterize)
Living Templates in Code
Instead of copy-paste documentation that gets outdated, our templates live in the codebase and evolve with our standards.
Test-First Development by Default
Every generator includes a well-structured test file. Here's the beautiful part: when the generator runs, the test starts 🟢 (passing with a basic "renders without crashing" assertion). As you implement the actual functionality, the test naturally goes 🔴 as you add real assertions, encouraging proper TDD practices.
Opinionated but Flexible
Our generators encode our team's preferences and best practices:
- Preferred styling approach (CSS modules, styled-components, etc.)
- Standard import ordering and formatting
- Consistent file naming and organization
- Pre-configured linting and formatting rules
- Integration with our monitoring and analytics tools
Real-World Impact
We now have generators for virtually every piece of our architecture:
- React Components (with variants for forms, modals, layouts)
- Redux Features (actions, reducers, selectors, sagas)
- NestJS Services (with database integration and validation)
- API Endpoints (with OpenAPI documentation)
- Full Applications (with routing, auth, and base components)
- Libraries (with proper build configuration and exports)
The Numbers
What used to take 15-20 minutes of setup time now takes 30 seconds. But the time savings are just the beginning:
- Zero setup errors: No more missing imports or typos in boilerplate
- Consistent patterns: Every team member follows the same conventions
- Faster onboarding: New developers can be productive immediately
- Living documentation: The generators show the "right way" to build features
- Easy evolution: When we want to change patterns, we update the generator and all new code follows the new standard
Lessons Learned
Start Simple, Evolve Gradually
Begin with your most common use case (for us, it was React components) and gradually add more sophisticated generators. Don't try to solve everything at once.
Make Templates Discoverable
Use nx list
to show available generators, and include good descriptions and examples in your generator schemas.
Embrace Prompts Over Flags
Interactive prompts are more user-friendly than remembering complex command-line flags, especially for infrequent users.
The Compound Effect
The real magic happens when generators become part of your team's DNA. During project planning, we naturally think in terms of the generators we'll need. "This feature needs a new service, two components, and a form, that's three generator commands."
What started as a solution to Redux boilerplate has evolved into a comprehensive development accelerator. The consistency, time savings, and reduced cognitive overhead compound over time, making the entire team more productive and the codebase more maintainable.
If you're dealing with repetitive setup tasks, inconsistent patterns, or lengthy onboarding processes, custom generators might be the productivity multiplier your team needs. Start small, measure the impact, and prepare to wonder how you ever developed without them.
Have you implemented custom generators in your workflow? I'd love to hear about your experiences and the patterns that have worked best for your team.