Skip to content

Org Manifests

Jannis Schreiber edited this page Jun 11, 2025 · 19 revisions

A org manifest is a complete definition of all packages and unpackaged metadata that should be "installed" on a given target org. The manifest describes the desired state, not the things that change with a particular release.

Manifest commands help you to validate and rollout org manifests. The engine has enough smartness to determine, if a particular artifact can be skipped to save time.

Key Concepts

At the top level, an org manifest consists of environments, artifacts, and options. The heart of a manifest is the list of Artifacts: they tell the engine what it needs to do. Artifacts have various types and are fundamentally just a "step to execute" in an ordered rollout plan. Environments allow you to deploy different variations of artifacts on Sandboxes and Production (for unpackaged artifacts), and Options let you configure some of the install/deploy behavior.

By convention, naming artifacts or environments follows snake_case. The entire manifest is rolled out through all environments (e.g. Dev, UAT, Prod). A rollout is complete, if all environments in your Org Hierarchy are in sync.

environments:
  dev: admin@example.com.dev
  qa: admin@example.com.qa
  prod: admin@example.com
artifacts:
  org_settings:
    type: Unpackaged
    path: src/unpackaged/org-settings
  apex_utils:
    type: UnlockedPackage
    package_id: 0Ho...
    version: 1.30.3
    skip_if_installed: false
  lwc_utils:
    type: UnlockedPackage
    package_id: 0Ho...
    version: 1.0.0
  core_crm:
    type: UnlockedPackage
    package_id: 0Ho...
    version: 3.1.2
  pims:
    type: UnlockedPackage
    version: 2.1.1
    package_id: ...
  pims_overrides:
    type: Unpackaged
    path: src/unpackaged/package-overrides/pims

Artifacts

The fundamental unit that drives a manifest. When a manifest is rolled out, its artifacts are evaluated one-by-one, in order of appearance. An artifact is composed of one to many steps, which are applied to the org. The exact steps are determined at runtime (the most common situation is when a package artifact is skipped, because package version is already installed on the target org).

The definition consists of an arbitrary name (e.g. apex_utils, sales, order_management, etc), the type discriminator, and its details. The rollout of a manifest is completed, when all steps of all artifacts were successfully applied.

artifacts:
  artifact_name_1:
    type: UnlockedPackage|Unpackaged|...
    flags: (--)full-flag-name(=value)

Overriding Command Flags

flags are optional and can be used to override anything. They are applied after the artifact is parsed. As the engine simply passes them through, you can technically use them to manually hard-code a --source-dir or --package. Consult the documentation of the underlying commands to understand available flags and how to use them.

The basic syntax for a flag is:

(--)flag-name(=value)

Meaning you must use the fully qualified name (apex-compile, not a), and you can optionally prefix with two dashes. If the flag requires a value (e.g. all or package), it is set = (no spaces). Multiple flags are separated by spaces. An example of a true/false flag and a key/value flag:

artifacts:
  artifact_name_1:
    type: Unpackaged
    path: ...
    flags: wait=20 concise ignore-conflicts

Artifact Types

An exhaustive list of all artifact types and how to configure them.

Unlocked Packages

Unlocked packages are the most obvious artifacts. They make use of a DevHub's native artifact registry. They are currently only supported, if the specified DevHub (at pipeline level) owns all packages. You must specify the package id (0Ho) and the desired version to install, so the engine can resolve it to the correct subscriber package version id (04t)

Unlocked packages are installed with the basic "sf package install" command and allow some additional options.

skip_if_installed (Optional, Default: true): If the desired package version is already installed on the target, this package is skipped. When a package is skipped, its overrides are skipped as well.

package_id (Required): ...

version (Required): ...

installation_key (Optional): ...

Handling Installation Keys

Installation keys are treated as secrets. You can't set them via command parameters or hard-code them in the manifest file. Instead, they are set as environment variables. Your plan file defines the variable name that is read for the installation key. If a package does not define an installation key variable name in the manifest, the engine tries to install it without a key.

pims:
  package_id: 0Ho0X0000000000AAA
  installation_key: PIMS_INSTALLATION_KEY
core_crm:
  package_id: 0Ho0X0000000001AAA
  installation_key: CORE_INSTALLATION_KEY

Injecting env-vars from keys.env is not yet implemented. Be patient.

If you want to run the command locally, you can store installation keys in a file and set the key-file as a parameter for the rollout command. For example, create a file keys.env in a folder secrets in your project with your installation keys.

# your actual installation keys - don't commit this!
PIMS_INSTALLATION_KEY=TJHfwVFUGw...
CORE_INSTALLATION_KEY=xiEdLdUQGoQ...
etc

Now, you can use this file when running the rollout command.

sf jsc manifest rollout --manifest my-org-manifest.yaml --installation-keys secrets/keys.env

Managed Packages

Not implemented yet.

Unpackaged

Any unpackaged metadata (in source format) can be specified as an "Unpackaged" artifact. A release manifest fundamentally does not distinguish between basic org settings, a package override or an unpackaged app. Its up to you how you organize the source files and configure your manifest to roll them out.

skip_if_unchanged (Optional, Default: true): Similar to an unlocked package, you can tell the engine to skip

Source Path

Each unpackaged artifact has two options: a single source path or a mapping of source paths per environment. A single path always deploys the same source, regardless of the target environment:

pims_overrides:
  type: Unpackaged
  path: src/package-overrides/pims/main

Individual paths for each environment can be specified for every env in the environments object. If you define individual paths, the engine only deploys mapped environments. In other words: If you define prod in your environments object, but do not specify a path for prod in package overrides, no post install source will be deployed, if the package is installed on prod.

pims_overrides:
  type: Unpackaged
  path:
    dev: src/package-overrides/pims/dev
    qa: src/package-overrides/pims/dev
    prod: src/package-overrides/pims/main

Cron Jobs

Not implemented yet

Garbage Disposal

Not implemented yet

Environments

Environments are optional, you only need to define them, if you want to deploy different source based on the target environment. They are the fundamental link between your Org Hierarchy, your pipeline implementation, and the release manifest.

environments:
  dev_env_name: my-username@example.com.dev
  prod_env_name: my-username@example.com

The engine evaluates the username of the target org it is currently deploying to. If it finds a match in the environments object, this match is used in SourceDeploy tasks (Unpackaged artifacts) to determine the source Path. There is no restriction on how many Sandboxes and/or Production envs you can add. It is mostly just a key/value pair that you can use in source-path configuration of unpackaged artifacts.

Options

Not yet implemented. Default behavior is executed

The behavior of the engine can be configured to certain aspects. If a setting can be set on manifest level and artifact level, the artifact always takes precedence, if present.

skip_if_installed (Default: true): For all package artifacts, skip installation if the resolved version is already installed

requires_promoted_versions (Default: true): Validate, that the package version is promoted and fail, if it isn't. Ignores if the target org is a Sandbox or Production.

strict_environments (Default: true): If false, ignores, if the target org is not present in mapped environments. If no match is found for a path-mapping, the step is skipped. If true, an error is raised.

pipefail (Default: true): If true, an error in the artifacts pipe fails the entire rollout. If false, the rollout proceeds (but other errors may occur, due to dependencies).

Use Cases

An overview of popular use cases and how to solve them with manifests.

Handling Multi-DevHub Environments

At the moment, the manifest command only supports a single DevHub. The DevHub is needed to resolve package versions (1.2.3) to the correct 04t... ids. If you have multiple DevHubs, you need to create one manifest.yaml per DevHub and call the sf jsc manifest rollout once per manifest.

Multi-Org Environments

The Org Manifest was written with heterogenous multi-org environments in mind. The key principle is decoupling the release process (package build and promote) from deployments (general artifact rollouts). At the highest level, you have one dedicated "master repository" per Org Hierarchy. That way, the repository can act as your deployment audit trail and has one manifest. The manifest tells you which artifacts are installed on the Orgs (we assume, that each hierarchy may be different). Changes to the manifest tell you what was released.

This concept builds on the 1-1-1 Repository Model.

Clone this wiki locally