Ignition
Guides

Resources Overview

The five built-in resources and how they work.

Resources are the building blocks of Ignition recipes. Each resource manages a specific aspect of server state.

The five resources

ResourcePurposeNature
aptManage system packagesDeclarative
fileManage file contents, permissions, ownershipDeclarative
directoryManage directoriesDeclarative
execRun arbitrary commandsImperative
serviceManage systemd servicesMixed

Declarative vs imperative

Declarative resources describe a desired end state. Ignition checks the current state and only makes changes if needed:

// Declarative: "nginx should be installed"
await apt({ name: "nginx", state: "present" })
// If already installed → ok (no action)
// If not installed → installs it → changed

Imperative resources always execute their action:

// Imperative: "run this command"
await exec({ command: "npm install" })
// Always runs → always reports changed

The service resource is mixed — started and stopped are declarative (they check first), while restarted and reloaded are imperative (they always execute).

Creating resources

Use createResources(ctx) to get bound resource functions:

import type { ExecutionContext } from "@grovemotorco/ignition"
import { createResources } from "@grovemotorco/ignition"

export default async function (ctx: ExecutionContext) {
  const { apt, file, directory, exec, service } = createResources(ctx)

  // Each function is bound to the current ExecutionContext
  await apt({ name: "curl", state: "present" })
}

Resource results

Every resource call returns a ResourceResult:

const result = await apt({ name: "nginx", state: "present" })

result.status // "ok" | "changed" | "failed"
result.type // "apt"
result.name // "nginx"
result.durationMs // execution time in milliseconds
result.current // observed state before execution (undefined on failure)
result.desired // target state from input (undefined on failure)
result.output // resource-specific output data (undefined on failure)

Status meanings

StatusMeaning
okAlready in the desired state. No changes made.
changedWas not in desired state. Changes were applied (or would be, in check mode).
failedAn error occurred during check or apply.

Resource call metadata

Pass metadata as the second argument to tag, identify, or annotate resource calls:

await apt({ name: "nginx", state: "present" }, { tags: ["web"], id: "install-nginx" })
FieldTypePurpose
tagsstring[]Call-level labels for programmatic filtering
idstringUnique identifier for this call
notifystring[]Notification labels (for future use)
sensitivePathsstring[]Redaction hints; not automatically enforced by the current CLI

CLI --tags filtering applies to recipe meta.tags, not per-resource call metadata.

Check-then-apply lifecycle

Every resource follows a two-phase cycle managed by executeResource():

  1. check() — inspects current state and decides whether changes are needed. Most built-in resources keep this read-only, but guarded exec currently runs its guard command during check().
  2. apply() — mutating. Only called if check() returned inDesiredState: false and the mode is apply.

This gives you:

  • Dry-runs skip applyignition run --check runs check() for every resource without calling apply(), but guarded exec still runs its guard command during check()
  • Safe re-runs — if everything is already correct, nothing changes
  • Explicit failures — any resource that can't converge reports failed

If you need strictly side-effect-free dry-runs, keep your check() logic and any exec guards read-only.

For the full API of each resource, see the individual reference pages:

On this page