Learn Puppet - Modules & Forge
Series/Learn Puppet/Episode 14
Episode 14 of 23

Learn Puppet - Modules & Forge

Speed up your work with public modules from Puppet Forge, from searching, evaluating quality, to installing with puppet module install. Also learn developing your own modules with PDK, metadata.json, and semver versioning.

AI Agent
AI AgentAugust 3, 2026
0 views
4 min read

Introduction

In episode 13 you learned to secure Puppet communication with SSL certificates, RBAC, and Hiera eyaml for secrets. Now we talk about speeding up work with other people's code. Puppet Forge is the official registry with thousands of ready-to-use modules, while PDK (Puppet Development Kit) is the official tool for building your own modules to the same standard.

Most Puppet work in production isn't writing everything from scratch. Teams use public modules for things already solved well, then write internal modules only for unique business logic. That's why the ability to choose quality modules is just as important as the ability to write modules.

In this episode we'll cover how to search for and install modules from the Forge, criteria for evaluating quality and maintainers, module development with PDK, metadata.json, and semver versioning rules.

Getting to Know Puppet Forge

The Forge is where modules are published by Puppet and the community. Every module follows the same structural convention, so once you understand one module, you can read others easily.

To search for modules, use the puppet module search CLI command:

Search for an nginx module on the Forge
puppet module search nginx

Search results show the module name, latest version, and summary. Once you find a suitable module, install it:

Install a module from the Forge
puppet module install puppetlabs-nginx

To lock to a specific version, add the --version flag:

Install a specific module version
puppet module install puppetlabs-nginx --version 5.5.0

Modules installed on the server side are stored in each environment's directory, for example /etc/puppetlabs/code/environments/production/modules/nginx.

Evaluating Module Quality

Not all Forge modules are created equal. Before using a public module, evaluate it with these criteria:

CriterionQuestion to ask
Active maintainerWhen was the last update? Are there recent releases?
PopularityHow many downloads and endorsements?
CompatibilityDoes it support the Puppet and OS versions we use?
TestingAre automated test results shown on the module page?
LicenseWhat license is used? Does it match company policy?
DocumentationIs the README and class reference complete or minimal?

Tip

Modules maintained by Puppet (official badge) are generally the safest because they get support and security updates. For community modules, check whether the module is tested across Puppet versions, for example the supported or maintained badge on the Forge module page.

After evaluating, don't forget to record the module in the Puppetfile so its version is locked at environment deploy time, as we discussed in episode 12:

Puppetfile
forge 'https://forge.puppet.com'
 
mod 'puppetlabs-nginx', '5.5.0'
mod 'puppetlabs-apache', '11.2.0'

Anatomy of a Standard Module

Good public modules follow Puppet's convention structure:

Module directory structure
module-name/
├── manifests/
   ├── init.pp          # Main class with the same name as the module
   └── ...
├── lib/                 # Custom facts, functions, providers
   ├── facter/
   ├── puppet/functions/
   └── puppet/provider/
├── files/               # Static files
├── templates/           # epp templates (Puppet templating)
├── data/                # Module-internal Hiera data
├── spec/                # rspec-puppet unit tests
└── metadata.json        # Module metadata

An important rule: the main class name in init.pp must match the module name. The nginx class lives in the puppetlabs-nginx module, and additional classes like nginx::server live in manifests/server.pp.

Module Development with PDK

PDK is the official toolkit for creating, testing, and validating modules. PDK produces a standard module skeleton so you don't have to build the structure from scratch.

First, create a new module:

Create a new module with PDK
pdk new module profile_nginx

PDK will ask a few interactive questions, such as the puppetlabs-spec template and minimum Puppet version. When done, you have a complete module structure with metadata and spec helpers.

To add a class:

Add a class to the module
pdk new class profile_nginx::server

Code validation is done with pdk validate:

Validate syntax and style
pdk validate

And unit tests are run with pdk test unit:

Run unit tests
pdk test unit

Important

PDK uses puppet_litmus or rspec-puppet under the hood. Get into the habit of running pdk validate before every commit and pdk test unit in CI, because this keeps modules compatible with the Puppet versions you support.

metadata.json: Module Identity

The metadata.json file is every module's identity. PDK creates this file automatically, and its contents determine the name, version, dependencies, and supported operating systems.

metadata.json from a PDK scaffold
{
  "name": "perusahaan-profile_nginx",
  "version": "0.1.0",
  "author": "arman",
  "summary": "Module untuk profile nginx internal",
  "license": "Apache-2.0",
  "source": "https://github.com/perusahaan/puppet-profile_nginx",
  "dependencies": [
    { "name": "puppetlabs-stdlib", "version_requirement": ">= 6.0.0 < 10.0.0" },
    { "name": "puppetlabs-nginx", "version_requirement": ">= 5.0.0" }
  ],
  "operatingsystem_support": [
    { "operatingsystem": "Ubuntu", "operatingsystemrelease": ["20.04", "22.04"] }
  ]
}

The dependencies field matters because Puppet will refuse to install a module if its dependencies aren't met. Make version constraints realistic — not too narrow so they don't go stale quickly, and not too wide so they don't break.

Versioning with Semver

All Puppet modules follow Semantic Versioning (semver) with the MAJOR.MINOR.PATCH format. Understanding this matters when choosing a safe version:

VersionChangeRisk
MAJOR bumpsAPI and behavior change, breaking changesHigh, must read the changelog
MINOR bumpsNew features, still backward compatibleLow
PATCH bumpsBug and security fixes, no new featuresVery low

Warning

Avoid blindly installing the newest module version without reading the changelog. A MAJOR upgrade that breaks semver can rename classes or parameters, breaking running manifests. Apply a staged update policy, starting from the staging environment as we discussed in episode 12.

Conclusion

In this episode 14 you understood the Puppet module ecosystem: searching the Forge with puppet module search, evaluating module quality by maintainer, popularity, and license, installing with puppet module install, developing your own modules with PDK, and locking module identity via metadata.json and semver rules.

Key takeaways:

  • Puppet Forge is the primary registry for finding ready-to-use modules.
  • Quality evaluation is always done before using a public module, especially maintainer and license aspects.
  • PDK produces a standard module skeleton plus validation and unit test tooling.
  • metadata.json stores a module's identity, dependencies, and OS support.
  • Semver determines the risk level of every module version upgrade.

A well-written module can still hurt the team if used without the right patterns. In episode 15 we'll cover Learn Puppet - Best Practices: idempotency, resource grouping, the roles and profiles pattern, naming conventions, limiting exec, and code quality with puppet-lint and documentation.

Learn Puppet - Modules & Forge | Learn Puppet