Beginners to configuration management often assume that Ansible is the “easy” option because it uses a simple YAML syntax and avoids installing an agent on every node.
However, the Progress Chef platform has undergone significant evolution in recent releases. It now offers a simple syntax with YAML and JSON recipes, agentless execution (using Target Mode), native local execution on Windows and Linux and a powerful test framework called Test Kitchen.
It also includes a Domain-Specific Language (DSL) that sits on top of Ruby, allowing you to describe resources and configuration in a human-readable way. These capabilities make Chef just as approachable – and more scalable – than Ansible while retaining the robustness that enterprises value.
This overview highlights how the modern Chef features simplify onboarding, whether you are writing your first recipe or managing thousands of servers.
Ansible is designed around YAML playbooks and an agentless push model. Ansible exclusively uses a push-based, agentless architecture; the control node uses SSH or WinRM to contact managed hosts, so no installation is required on the node. Its tasks are written in YAML, which is human-readable and easy for beginners. The quick setup and lightweight footprint make Ansible appear to be more attractive for small environments or when you only need to run ad‑hoc tasks.
Progress Chef Infra Client (the configuration engine behind Chef) has historically required an agent (the Chef Client) and uses a pull-based model: each node periodically requests configuration from the Chef Server. Chef DSL is built on Ruby semantics and allows you to describe resources declaratively, offering greater flexibility but potentially making it feel more like programming to newcomers. This architecture gives Chef autonomy and scalability, but has contributed to the perception that it is “harder."
Let’s look at the features that make the Chef solution easier, if not better than Ansible:
Many newcomers prefer Ansible’s YAML because it feels declarative. Chef has closed this gap by introducing support for YAML and JSON recipes. JSON and YAML recipes let you define Chef resources using a no-code syntax; they are meant for users who prefer declarative YAML or JSON over writing recipes in the Chef DSL. YAML recipes were introduced in Chef Infra Client 16.0 and .yml file support arrived in 17.2.29; JSON recipe support was added in Chef Infra Client 18.8.
To write a YAML or JSON recipe, you create a file in your cookbook’s recipes directory and define the resources array. Each item has a type, name and relevant properties. For example, the following YAML recipe installs Nginx and starts the service:
# cookbooks/my_cookbook/recipes/default.yml
resources:
- type: "package"
name: "nginx"
action: "install"
- type: "service"
name: "nginx"
action: ["enable", "start"]The same logic expressed in JSON looks like this:
{
"resources": [
{
"type": "package",
"name": "nginx",
"action": "install"
},
{
"type": "service",
"name": "nginx",
"action": ["enable", "start"]
}
]
}For more complex tasks, you can still write traditional Chef DSL (files ending in .rb). These recipe books offer loops, conditionals, notifications and access to node attributes. Under the hood, the Chef DSL leverages Ruby, and you can embed Ruby for advanced use cases when the DSL alone isn't enough. For example, a Chef DSL recipe book to install and configure Nginx looks like this:
# Cookbook:: nginx_example
# Recipe book:: default
# Installs nginx and ensures the service is enabled and started
package 'nginx' do
action :install
end
service 'nginx' do
action [:enable, :start]
endProgress Chef encourages a hybrid approach: use YAML or JSON recipes for simple static configurations and Chef DSL recipe books when you need dynamic logic or complex resource relationships.
Traditionally, you would install Chef Client on each node. Now, Chef also provides an agentless mode of deployment with Target Mode. Chef can now run on machines that do not have the Chef Client installed. This way, Chef Infra Client executes against remote systems, edge devices, cloud resources, or network equipment that the host can reach, without agents deployed.
To use Target Mode, you create a credentials file (TOML format) specifying connection details for each target – host, user, SSH key/password and other options. A simple credentials file might look like this:
['HOST-1']
host = '192.168.0.10'
user = 'admin'
key_files = '~/.ssh/id_rsa'
transport_protocol = 'ssh'To run a cookbook on a target, you simply call:
chef-client -t HOST-1 path/to/cookbookChef will connect via SSH and apply the cookbook on the remote system without installing the Chef Client. You can also combine this with Local Mode by adding -z: chef-client -z -t HOST-1. This approach gives you agentless automation similar to Ansible while benefiting from Chef resource model and idempotency.
While “agentless" is ideal for devices where you cannot install software, we often recommend using the agent mode for servers. In this model, the Chef Client is installed on each node and periodically pulls configuration from the Chef Server. This pull‑based model ensures that configurations are applied regularly and consistently. It is especially valuable in large environments where nodes may be unreachable via SSH or where security policies require local execution.
On the other hand, Ansible cannot run locally on Windows but can manage it via WinRM, whereas Chef runs natively on Linux and Windows. If your environment includes Windows servers or desktops, native agent mode from Chef simplifies configuration management without relying on SSH, WinRM or PowerShell remoting, making endpoint management more secure and easier than ever.
The Local Mode in Chef (chef-client --local-mode or -z) uses chef‑zero, an in‑memory Server, to run Chef against your local repository. Local mode lets you run Chef against your code on your workstation as if it were a server; This means you can develop and test cookbooks quickly without provisioning a server. Local mode supports data bags, roles, environments and search, so it’s a full-fledged development environment. When local mode is paired with Test Kitchen, Chef provides end-to-end developer tooling.
One of the biggest advantages that Chef has over Ansible is its robust testing ecosystem. Test Kitchen, included with Chef Workstation. It spins up containers, virtual machines or cloud instances, runs your cookbook and then validates the result using Chef InSpec tests. Test Kitchen automatically creates a sandbox environment, installs Infra Client, runs your cookbooks (also referred to as converging your configuration) and allows you to run InSpec tests for easy local validation. Each test runs against an isolated instance defined in a kitchen.yml file, which specifies the driver (e.g., Vagrant, EC2, Docker), provisioner (e.g., chef_zero), transport (SSH/WinRM) and test suites.
For example, a kitchen.yml might look like this:
driver:
name: vagrant
provisioner:
name: chef_zero
platforms:
- name: ubuntu-20.04
- name: windows-2019
suites:
- name: default
run_list:
- recipe[nginx_example::default]
verifier:
name: inspecRunning the kitchen test will bring up an Ubuntu and a Windows VM, apply your cookbook, and execute InSpec tests to verify the configuration. This workflow encourages test‑driven infrastructure and dramatically increases confidence before deploying changes to production.
Sometimes you want to move a machine into a desired state without creating an entire cookbook. Chef includes a handy command called chef‑apply. Chef‑apply runs a single recipe from the command line; it is a great way to explore resources and provides extensive post-provisioning configuration for autoscaling cloud resources or cloud VMs by sending the recipe as part of the user data script. The syntax is straightforward:
chef-apply name_of_recipe.rb
You can also pass a recipe inline. For example, to install the nano text editor on a test machine:
sudo chef-apply -e "package 'nano'"
When you run this command, Chef will immediately converge the system and show you the actions taken. Chef-apply is perfect for learning the Chef DSL, experimenting with resources, or embedding the power of Chef into your applications and ecosystem.
Although built-in resources within Chef cover the majority of operational tasks like managing packages, files and services, the platform can be easily extended by defining custom resources. A custom resource is a simple extension of the Chef Infra Client that adds your own resources into the Chef DSL; it is implemented and shipped as part of a cookbook, follows easy, repeatable syntax patterns, leverages built-in resources and is reusable! Once defined, the custom resource can be called in any recipe like a built‑in resource. This approach encapsulates repeated logic, making your code more reusable.
Another key Chef advantage is the Compliance Phase (introduced in Chef Infra Client 17). The compliance phase automatically executes Chef InSpec compliance profiles as part of every Chef Infra Client run. The compliance phase lets you automatically execute compliance audits, verify configurations, or perform what-if analysis of changes before you make them. Turning on the compliance phase is easy! Just set the node['audit']['compliance_phase'] attribute to true and specify which InSpec profiles to run. This built-in phase integrates security and compliance checks directly into configuration management and removes the need to manage separate tools.
The extensibility and flexibility that Chef provides is unmatched. Chef allows you to build abstractions tailored to your environment while enforcing security and compliance automatically.
A capability that makes it stand out from its competitors.
| Aspect | Ansible | Chef |
| Architecture | Agentless; control node pushes tasks via SSH/WinRM. | Agent‑based by default; each node pulls policies from Chef Server. Also provides you the option of agentless across multiple protocols. |
| Supported OS | Runs on most Linux/Unix; manages Windows via WinRM. | Runs natively on Linux, Windows and Unix; supported versions include Windows 10/11/2022/2025. |
| Language | Tasks defined in YAML; easy to read. | Recipes traditionally use the Chef DSL (built on Ruby); now, they also use YAML and JSON for simpler cases. |
| Execution model | Push - run when triggered. | Pull - nodes converge on a schedule; Target Mode supports push-like agentless run; Local Mode for development. |
| Testing | Limited built-in testing; relies on external tools. | Test Kitchen and Chef InSpec provide automated VM/cloud testing and compliance validation. |
| Learning curve | Quick to start, especially for simple tasks. | Steeper for the Chef DSL; easier for beginners thanks to YAML/JSON recipes; consistent resource model and advanced features for complex environments. |
Ansible’s minimal setup makes it appealing for quick tasks, but Chef offers a richer feature set without sacrificing approachability. New YAML and JSON recipes make Chef look and feel like Ansible for straightforward workloads, while Chef DSL recipes remain available for powerful, programmatic logic. Agentless execution eliminates the need to install the Chef Client on every machine, giving you agentless automation similar to Ansible but with robust idempotency and the resource model of Chef. Local Mode and Test Kitchen make it simple to develop and validate your cookbooks on your workstation or spin up disposable test environments.
In other words, Chef has evolved from a DSL-heavy, server-centric tool into a flexible platform that meets you where you are.
If you’re evaluating configuration‑management tools, don’t be misled by myths! Chef capabilities make it easier to adopt and scale than Ansible, especially when testing, compliance and heterogeneous environments are a concern.
In the next blog, we will delve into custom resources and the compliance phase in greater detail. We will also discuss advanced features, including policy files, resource guards and notifications.
Stay tuned!