Roles & profiles
The standard design pattern.
Roles and profiles is the near-universal design pattern for organizing a Puppet codebase, and it exists because ad-hoc class assignment becomes unmaintainable. A profile is a wrapper class that configures one technology stack the way your organization wants it (profile::nginx pulls in the nginx module and sets your standards). A role composes profiles into a machine type (role::web includes profile::base + profile::nginx + profile::app). Each node is assigned exactly one role.
# profile: your opinionated use of a component moduleclass profile::nginx {class { 'nginx': workers => 4 }include profile::firewall::web}# role: compose profiles into a machine typeclass role::web {include profile::baseinclude profile::nginxinclude profile::app}# node gets exactly one role (via Hiera or node definition)# role: 'role::web'
Why the discipline pays off
The rules are strict on purpose: roles only include profiles (no resources), profiles are the only place that declares component classes with parameters and does Hiera lookups, and nodes get one role. This keeps the codebase navigable at scale — you always know where a decision lives — and makes machine types self-documenting. It is the single most important structural convention in real Puppet.