Learn Puppet - Manifests & Resource Types
Episode 4 of 23

Learn Puppet - Manifests & Resource Types

The foundation of the Puppet language: manifest structure, the anatomy of a resource type with title, parameters, and properties, seven core resource types, the declarative and idempotent concepts, and local testing with puppet apply.

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

Introduction

In the previous episode 3, you successfully built your Puppet lab — the server and agent are connected via SSL certificates, and the first agent run went smoothly. However, the applied catalog is still empty because you haven't written anything yet. Episode 4 is when we fill that catalog: we'll learn writing manifests with resource types — the foundation of the Puppet language you'll use every day.

Manifest: The Home of Configuration

A manifest is a Puppet file with the .pp extension that contains configuration code. This is where you declare resources. A manifest can be applied directly to a local machine with puppet apply, or compiled by the server into a catalog for remote nodes.

A manifest contains one or more resource declarations. Here's a minimal manifest example:

example.pp: a minimal manifest
package { 'curl':
  ensure => installed,
}
 
file { '/etc/motd':
  ensure  => file,
  content => 'Welcome to my managed server',
}

Notice the pattern: you declare the end state, not the steps. This is a fundamental difference from scripting.

The Anatomy of a Resource Type

Every resource declaration has three parts:

  • Type — the kind of resource, for example package, service, or file.
  • Title — a unique name that identifies the resource.
  • Parameters — attributes that determine the resource's properties and behavior.
Anatomy of a resource declaration
package { 'nginx':
  ensure => '1.18.0',
}

In the example above, package is the type, nginx is the title, and ensure => '1.18.0' is a parameter. Some parameters are called properties — parameters that describe the desired state and are checked by the agent, for example ensure, content, mode. Non-property parameters only control how the resource is created, for example before, require, or provider.

PartExampleRole
TypepackageSystem element abstraction
Title'nginx'Unique resource identity
Propertyensure => runningState that is checked & converged
Parameterrequire => Package['nginx']Controls ordering and behavior

Core Resource Types

These seven resource types are the ones you'll use most often:

package

Manages packages through the package manager (apt, dnf, yum).

The package resource
package { 'nginx':
  ensure => installed,
}

The ensure value can be installed/present (installed), absent (removed), latest (always the newest version), or a specific version number.

service

Manages systemd services (or init).

The service resource
service { 'nginx':
  ensure => running,
  enable => true,
}

ensure => running makes sure the service is up; enable => true makes sure it starts at boot.

file

Manages files and directories — content, ownership, and permissions.

The file resource
file { '/etc/nginx/nginx.conf':
  ensure  => file,
  owner   => 'root',
  group   => 'root',
  mode    => '0644',
  source  => 'puppet:///modules/nginx/nginx.conf',
}

exec

Runs external commands — for things no other resource can handle. Note the unless guard to stay idempotent.

An idempotent exec resource
exec { 'download-release':
  command => 'wget -O /tmp/app.tar.gz https://example.com/app.tar.gz',
  path    => ['/usr/bin', '/bin'],
  unless  => 'test -f /tmp/app.tar.gz',
}

user and group

Manages system accounts and groups.

The user and group resources
group { 'app':
  ensure => present,
}
 
user { 'app':
  ensure     => present,
  gid        => 'app',
  shell      => '/usr/sbin/nologin',
  managehome => false,
}

cron

Manages cron jobs.

The cron resource
cron { 'backup-daily':
  command => '/usr/local/bin/backup.sh',
  minute  => 0,
  hour    => 2,
}

Note

There are about two dozen built-in Puppet resource types — including mount, exec, host, selinux, and notify. You can view the full documentation for any type with puppet describe package or puppet describe file.

Declarative and Idempotent

Puppet's declarative nature means: you declare the outcome, and Puppet decides how to achieve it. From this property comes idempotency — running a manifest repeatedly produces the same end state, with no side effects from repetition.

puppet apply can be run repeatedly
puppet apply nginx.pp
puppet apply nginx.pp
puppet apply nginx.pp

The first run makes changes; the second and third runs only verify that the state is already correct — that's why the agent is safe to run on a 30-minute schedule.

Important

Idempotency is a contract between the manifest author and the system. The exec resource is the exception that most often breaks this contract — without a guard like unless or onlyif, exec will run its command on every agent run. Use exec only when no other resource can do the job, and always give it a guard.

Testing Manifests with puppet apply

Before a resource goes out to other nodes, test it locally first. puppet apply applies a manifest directly to the machine you're on — the fastest way to validate syntax and behavior.

nginx.pp: install and run nginx
package { 'nginx':
  ensure => installed,
}
 
service { 'nginx':
  ensure => running,
  enable => true,
  require => Package['nginx'],
}
Apply the manifest locally
sudo puppet apply nginx.pp

Notice the require => Package['nginx'] relationship on the service — this parameter ensures the package is installed before the service is managed. This is an example of ordering, which we'll go deeper into when we cover classes and modules.

Tip

Use puppet apply --noop for a dry run: Puppet will show the changes it would make without actually applying them. Combining --noop with --verbose is very useful for inspecting what would change before executing.

Conclusion

In this episode 4 you mastered the foundation of the Puppet language: understanding manifest structure, dissecting the anatomy of a resource declaration with type, title, and parameters, getting to know the seven core resource types (package, service, file, exec, user, group, cron), and testing manifests locally with puppet apply.

Key takeaways:

  • A .pp manifest is the home of configuration; resource declarations are its content.
  • A resource = type + title + parameters; properties describe the desired state.
  • Declarative & idempotent — declare the end state, run as often as you like, the result stays the same.
  • exec needs a guard (unless/onlyif) so it doesn't break idempotency.
  • puppet apply --noop is the go-to dry run before applying.

In the next episode, episode 5, we'll level up: classes, modules & roles/profiles — organizing manifests into reusable classes, understanding the full module structure, and applying the Roles/Profiles pattern that's the industry standard for keeping the class hierarchy clean. Get your PDK ready, because the next episode is packed with hands-on work!

Learn Puppet - Manifests & Resource Types | Learn Puppet