The closing episode of the Learn Puppet series: a thorough comparison of Puppet with Ansible, Chef, SaltStack, and Terraform and Pulumi, when to choose each, a reflection on the journey from episode 0 to 21, a production-grade infrastructure-as-code checklist, the future direction of Puppet with Enterprise, SCM, and cloud-native, and official references to keep learning.

This is the final episode. Over the previous 21 episodes you went from zero: understanding why configuration management exists, writing manifests and modules, using Hiera and PuppetDB, securing communication with SSL, all the way to assembling a production-ready architecture. Episode 21 wrapped up the technical material with a production-ready architecture — Puppet Server with high availability, PuppetDB on PostgreSQL, Code Manager, a CI/CD pipeline, and backup strategy.
Episode 22 isn't about new features anymore; it's about looking outward and forward. We'll place Puppet on the configuration management map and compare it with Ansible, Chef, SaltStack, as well as Terraform and Pulumi — then recap the whole journey from episode 0 to 21, leave you a checklist for production-grade infrastructure, and point to references and future directions to keep growing.
Puppet isn't the only player in the field. Every tool makes different design decisions — language, push or pull model, presence of an agent, and need for a central server — and those decisions determine when the tool is the right choice. Let's look at the full map.
Puppet uses the highly declarative Puppet DSL, a pull-based model (an agent on the node pulls a catalog from the server), and requires a central server — Puppet Server or Puppet Enterprise. Its strengths lie in a firm desired state, a resource graph with dependencies between resources, built-in reporting and compliance through PuppetDB, and full enterprise support. Its weaknesses: a DSL more rigid than Ruby or Python, and the unavoidable operational complexity of a server.
Ansible declares state in YAML and applies it with a push model: from one control node, over SSH to targets. With no agent and no central server, Ansible excels at simplicity and onboarding — small teams can be productive within minutes. Its weaknesses: no state is maintained between runs, it depends heavily on stable SSH connections, and scheduled convergence has to be set up from outside.
Chef uses a Ruby DSL with units called cookbooks, a pull-based model with an agent (chef-client) that pulls policies from the Infra Server. Ruby's flexibility makes Chef very expressive for configuration logic, and its ecosystem is complete via InSpec and Chef Automate. Its weaknesses: the Ruby learning curve and the complexity of operating a central server, similar to Puppet.
SaltStack (Salt) offers a hybrid model: minions can be pushed or pulled, it's written in Python, with highly flexible targeting and fast parallel execution. Salt is strong for large-scale ad-hoc orchestration and environments needing quick response. Its weaknesses: a smaller ecosystem and documentation that sometimes lags behind the main players.
Terraform and Pulumi aren't configuration management — they're Infrastructure as Code for provisioning: declaring infrastructure (instances, network, storage) through cloud providers, not in-machine configuration. Terraform uses HCL, while Pulumi uses general-purpose programming languages like TypeScript, Python, or Go. Both work alongside Puppet rather than replacing it — for example, Terraform creates the instance, then Puppet configures it.
The best way to understand the philosophical differences is to see the same intent written in two tools. Here's the same nginx installation: once in an Ansible playbook, once in a Puppet class.
- hosts: web
become: true
tasks:
- name: Install nginx
ansible.builtin.apt:
name: nginx
state: present
- name: Ensure nginx running
ansible.builtin.service:
name: nginx
state: started
enabled: trueThe most striking difference: an Ansible playbook is a sequence of steps pushed from a control node over SSH, while a Puppet class is a desired state declaration pulled by an agent from the server. Ansible execution is done with ansible-playbook site.yml, while Puppet waits for the agent to run puppet apply --test on a scheduled interval — and the result is always reconverged if it drifts.
| Tool | Language | Model | Agent | Central server | Main focus |
|---|---|---|---|---|---|
| Puppet | Puppet DSL | Pull | Yes | Yes (PE) | Enterprise desired state |
| Ansible | YAML | Push | No | No | Simple ad-hoc configuration |
| Chef | Ruby DSL | Pull | Yes | Yes | Configuration and compliance |
| SaltStack | Python | Hybrid | Yes | Optional | Large-scale orchestration |
| Terraform | HCL | Push | No | Optional | Infrastructure provisioning |
| Pulumi | TS/Python/Go | Push | No | Optional | Provisioning via general-purpose languages |
No tool wins in every dimension — there's a right tool for each context:
Tip
Real-world needs are almost always multi-tool: Terraform for provisioning, Puppet or Ansible for configuration, and one orchestration tool for coordination. The skills you built in this series — thinking in desired state and idempotency — apply to all tools, because the underlying concepts are the same.
Let's glance at the map you've traveled:
Notice the pattern behind that sequence: every episode locks in the previous capabilities. You can't design a production architecture without understanding catalogs, and you can't understand catalogs without understanding manifests. This is a curriculum deliberately designed so each skill stands on top of another.
To solidify, here's a checklist that sums up all the lessons — use it as the minimum standard whenever you build infrastructure:
puppet-lint for style, rspec-puppet for unit tests, and acceptance tests for real machines, all running in CI.One thing ties it all together: habits. This checklist only matters if it becomes part of your team's way of working. Before starting a new project, make sure the tooling in your environment is consistent — verify versions with puppet --version and puppetserver --version:
puppet --version
puppetserver --version
pdk --version
bolt --version
r10k --version
puppet-lint --versionWhere is Puppet heading? Three directions to follow:
Important
Always verify the versions in your own environment. The versions mentioned in this article will keep moving — read the official release notes and run puppet --version and puppetserver --version to confirm compatibility before upgrading.
Curiosity is your biggest asset. Here are starting points to continue the journey:
pdk new module to write modules with built-in structure and linting.puppet-lint modules/nginx/manifests/init.pp to enforce code style.puppetlabs_spec_helper.eyaml encrypt -l db_password to encrypt hiera.bolt command run uptime --nodes web1.example.net for orchestration, r10k deploy environment production for environment deployment.Don't stop at documentation — read popular modules on the Forge, follow the release notes, and build something. The skills you've built will keep serving you as long as you practice them.
And here, the 23-episode journey (0 to 22) of Learn Puppet comes to an end. You've traversed every layer: from prerequisites and history, concepts and architecture, manifests and resource types, modules and roles/profiles, facts and Hiera, catalogs and PuppetDB, the console and orchestration, Code Manager and security, testing and troubleshooting, to the latest features and production architecture — and now the ecosystem and final reflection.
Key takeaways:
The skills you built aren't tied to one tool — they make you a better engineer in any tool. Thank you for sticking with it to the last episode. Practice the checklist, share your modules, and make idempotency instinctual. Go build infrastructure you can trust!