Anthony Wentzel

Yeoman generators: code conventions you can run

A Yeoman generator from our Freebird partner portal ended up in three React codebases. What code generation got right about team conventions.

From 2017 · 2 min read · Published August 30, 2026

In early 2017, the Freebird partner portal was a React app built by a small team moving fast. Rich Tillman, one of the engineers, did something that kept paying off: instead of writing a style guide for how components and Redux modules should look, he wrote a Yeoman generator.

What the Yeoman generator produced

The portal used Yeoman with three local generators:

  • component: a React component in one of three flavors (full, pure, or stateless), a stylesheet, and a test.
  • duck: a Redux module in the "ducks" pattern, with action types, reducer, action creators, and an API file, plus tests.
  • view: a routed screen with a container and component split.

Run it, answer a prompt, and you had a working, tested file that looked exactly like every other file of its kind. Here's the start of the duck template:

generator/duck/templates/duck.fetch.js
export const FETCH_EXAMPLE = '<%= projectActionPrefix %>/<%= duckName %>/FETCH_EXAMPLE'
export const FETCH_EXAMPLE_SUCCESS = '<%= projectActionPrefix %>/<%= duckName %>/FETCH_EXAMPLE_SUCCESS'
export const FETCH_EXAMPLE_ERROR = '<%= projectActionPrefix %>/<%= duckName %>/FETCH_EXAMPLE_ERROR'
export const FETCH_EXAMPLE_CANCELLED = '<%= projectActionPrefix %>/<%= duckName %>/FETCH_EXAMPLE_CANCELLED'
 
const InitialState = new Record({
  phase: INIT, 
  exampleThings: List(),
  error: null
})

Two conventions are baked in there that a style guide would have struggled to enforce:

  1. Every async module tracks a phase (INIT, LOADING, SUCCESS, ERROR), including a CANCELLED action that resets to INIT. No screen ever had to guess whether it was loading.
  2. Action types are namespaced with a project prefix. The generator asks for the prefix once and stores it for the project, so nobody can forget it.

Why it traveled

When I started new React projects later in 2017 and 2018, including a health platform's web app and its successor, the generator folder came with them. Same component flavors, same ducks, same tests. The later version added Storybook story templates and snapshot tests to the component generator, but the shape was the same.

That's the part I didn't expect. A generator is portable in a way a wiki page isn't. You copy one folder and your new project has the old project's conventions, enforced from the first file.

What's changed since

Redux ducks and Immutable records aren't what I'd reach for today. The idea underneath still holds, and it has a modern form: project templates, shadcn-style component registries, and increasingly, instructions for AI coding agents. When an agent writes code in our repos now, it follows conventions written down in files next to the code. That's the same bet Rich made in 2017: conventions work best when they're executable.


Related: One monorepo template, four products · Wait for the CloudFront invalidation: deploying a SPA to S3