Boilerplate to Generators

Boilerplate to Generators
How custom generators transformed our development workflow from inconsistent snowflakes to standardized, scalable patterns.

Boilerplate to Generators

June 21, 2025

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.