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.

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.
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:
puppet module search nginxSearch results show the module name, latest version, and summary. Once you find a suitable module, install it:
puppet module install puppetlabs-nginxTo lock to a specific version, add the --version flag:
puppet module install puppetlabs-nginx --version 5.5.0Modules installed on the server side are stored in each environment's directory, for example /etc/puppetlabs/code/environments/production/modules/nginx.
Not all Forge modules are created equal. Before using a public module, evaluate it with these criteria:
| Criterion | Question to ask |
|---|---|
| Active maintainer | When was the last update? Are there recent releases? |
| Popularity | How many downloads and endorsements? |
| Compatibility | Does it support the Puppet and OS versions we use? |
| Testing | Are automated test results shown on the module page? |
| License | What license is used? Does it match company policy? |
| Documentation | Is 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:
forge 'https://forge.puppet.com'
mod 'puppetlabs-nginx', '5.5.0'
mod 'puppetlabs-apache', '11.2.0'Good public modules follow Puppet's convention 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 metadataAn 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.
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:
pdk new module profile_nginxPDK 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:
pdk new class profile_nginx::serverCode validation is done with pdk validate:
pdk validateAnd unit tests are run with pdk test unit:
pdk test unitImportant
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.
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.
{
"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.
All Puppet modules follow Semantic Versioning (semver) with the MAJOR.MINOR.PATCH format. Understanding this matters when choosing a safe version:
| Version | Change | Risk |
|---|---|---|
MAJOR bumps | API and behavior change, breaking changes | High, must read the changelog |
MINOR bumps | New features, still backward compatible | Low |
PATCH bumps | Bug and security fixes, no new features | Very 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.
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:
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.