﻿---
title: changelog bundle cli command
description: Aggregates changelog YAML files matching a filter into a single bundle file. The bundle is the artifact used by the {changelog} directive and docs-builder...
url: https://docs-v3-preview.elastic.dev/elastic/docs-builder/pull/3804/cli/changelog/bundle
products:
  - Elastic Docs Builder
---

# changelog bundle cli command
```bash
docs-builder changelog bundle \
  [<profile>] \
  [<profile-arg>] \
  [<profile-report>] \
  [options]
```

Aggregates changelog YAML files matching a filter into a single bundle file. The bundle is the artifact used by the `{changelog}` directive and `docs-builder changelog render` to produce release notes.
The command has **two mutually exclusive modes**. You cannot mix them: supplying a profile name on the command line disables all filter and output flags (refer to [Options](#options) for equivalent changelog configuration settings).

## Arguments

<definitions>
  <definition term="<profile> string">
    Profile name from bundle.profiles in config (for example, "elasticsearch-release"). Used as the first positional argument in profile-based commands. The equivalent configuration entry is bundle.profiles.<name>.
  </definition>
  <definition term="<profile-arg> string">
    Version number or promotion report URL/path when using a profile (for example, "9.2.0" or "[https://buildkite.../promotion-report.html](https://buildkite.../promotion-report.html)"). Required second positional argument in profile-based commands.
  </definition>
  <definition term="<profile-report> string">
    Promotion report, URL list file, or changelog path list file when also providing a version. When provided, the second argument must be a version string and this is the filter source (for example, "bundle serverless-release 2026-02 ./report.html"). Optional third positional argument in profile-based commands.
  </definition>
</definitions>


## Options

<definitions>
  <definition term="--[no-]all">
    Include all changelogs in the directory. This option is not supported in profile-based commands. The equivalent configuration option is bundle.profiles.<name>.products: "* * *".
    **Default:** `false`
  </definition>
  <definition term="--config string">
    Path to the changelog.yml configuration file. Defaults to 'docs/changelog.yml' in option-based mode. This option is not supported in profile-based commands; configuration is auto-discovered.
    **Constraints:** symbolic links not allowed, must exist, extensions: yml, yaml
  </definition>
  <definition term="--directory string">
    Directory containing changelog YAML files. Uses config bundle.directory or defaults to current directory. This option is not supported in profile-based commands. The equivalent configuration option is bundle.directory.
    **Constraints:** symbolic links not allowed
  </definition>
  <definition term="--description string">
    Bundle description text with placeholder support ({version}, {lifecycle}, {owner}, {repo}). Overrides bundle.description from config. In option-based mode, placeholders require --output-products. This option is not supported in profile-based commands. The equivalent configuration options are bundle.description or bundle.profiles.<name>.description.
  </definition>
  <definition term="--hide-features string[]">
    Feature IDs (comma-separated) or a path to a newline-delimited file. Entries with matching feature-id values are hidden when the bundle is rendered. This option is not supported in profile-based commands. The equivalent configuration option is bundle.profiles.<name>.hide_features.
    **Repeatable:** pass `--hide-features` multiple times to supply more than one value
  </definition>
  <definition term="--[no-]no-release-date">
    Skip auto-population of release date in the bundle. Mutually exclusive with --release-date. This option is not supported in profile-based commands. The equivalent configuration options are bundle.release_dates: false or bundle.profiles.<name>.release_dates: false.
    **Default:** `false`
  </definition>
  <definition term="--release-date string">
    Explicit release date for the bundle in YYYY-MM-DD format. Overrides auto-population behaviour. Mutually exclusive with --no-release-date. This option is not supported in profile-based commands; use option-based mode, or set bundle.release_dates in configuration to control auto-population.
  </definition>
  <definition term="--input-products string">
    Filter by products in format "product target lifecycle, ..." (for example, "cloud-serverless 2025-12-02 ga, cloud-serverless 2025-12-06 beta"). All three parts are required but can be wildcards (*). This option is not supported in profile-based commands. The equivalent configuration option is bundle.profiles.<name>.products.
  </definition>
  <definition term="--output string">
    Output path for the bundled changelog (directory or .yml/.yaml file). Uses config bundle.output_directory or defaults to 'changelog-bundle.yaml' in the input directory. This option is not supported in profile-based commands. The equivalent configuration option is bundle.profiles.<name>.output.
  </definition>
  <definition term="--output-products string">
    Explicitly set the products array in the output file in format "product target lifecycle, ...". This option is not supported in profile-based commands. The equivalent configuration option is bundle.profiles.<name>.output_products.
  </definition>
  <definition term="--issues string[]">
    Filter by issue URLs (comma-separated), or a path to a newline-delimited file containing fully-qualified GitHub issue URLs. Can be specified multiple times. This option is not supported in profile-based commands. Pass a promotion report as the second or third positional argument instead, or set source: github_release on the profile.
    **Repeatable:** pass `--issues` multiple times to supply more than one value
  </definition>
  <definition term="--files string[]">
    Filter by changelog YAML paths (comma-separated), or a path to a newline-delimited file containing changelog paths. Can be specified multiple times. Forces local entry sourcing. This option is not supported in profile-based commands; pass a path list file as the second or third positional argument instead.
    **Repeatable:** pass `--files` multiple times to supply more than one value
  </definition>
  <definition term="--[no-]force-local">
    Force local entry sourcing for this run (equivalent to bundle.use_local_changelogs: true without editing config). Allowed in profile-based commands.
    **Default:** `false`
  </definition>
  <definition term="--owner string">
    GitHub repository owner for PR/issue numbers or --release-version. Falls back to bundle.owner or "elastic". This option is not supported in profile-based commands. The equivalent configuration options are bundle.owner or bundle.profiles.<name>.owner.
  </definition>
  <definition term="--branch string">
    Branch whose CDN changelog entry pool (changelog/{org}/{repo}/{branch}/...) is sourced from. Falls back to bundle.branch or "main". This option is not supported in profile-based commands. The equivalent configuration options are bundle.branch or bundle.profiles.<name>.branch.
  </definition>
  <definition term="--[no-]plan">
    Emit GitHub Actions step outputs (needs_network, needs_github_token, output_path, and cdn_url when a product is resolvable) describing network requirements, the resolved output path, and the public CDN URL of the scrubbed bundle, then exit without generating the bundle. Intended for CI actions. Supported in profile-based commands.
    **Default:** `false`
  </definition>
  <definition term="--prs string[]">
    Filter by pull request URLs (comma-separated), or a path to a newline-delimited file containing fully-qualified GitHub PR URLs. Can be specified multiple times. This option is not supported in profile-based commands. Pass a promotion report as the second or third positional argument instead, or set source: github_release on the profile.
    **Repeatable:** pass `--prs` multiple times to supply more than one value
  </definition>
  <definition term="--release-version string">
    GitHub release tag to use as a filter source (for example, "v9.2.0" or "latest"). Fetches PR references from release notes. This option is not supported in profile-based commands. The equivalent configuration option is bundle.profiles.<name>.source: github_release.
  </definition>
  <definition term="--repo string">
    GitHub repository name for PR/issue numbers or --release-version. Falls back to bundle.repo or the product ID. This option is not supported in profile-based commands. The equivalent configuration options are bundle.repo or bundle.profiles.<name>.repo.
  </definition>
  <definition term="--report string">
    URL or file path to a promotion report; extracts PR URLs as the filter. This option is not supported in profile-based commands. Pass the report as the second or third positional argument instead.
  </definition>
  <definition term="-l --log-level enum">
    Minimum log level.
    **Values:** trace, debug, information, warning, error, critical, none
    **Default:** `information`
  </definition>
  <definition term="-c --config-source enum">
    Override the configuration source: local, remote
    **Values:** local, remote, embedded
  </definition>
  <definition term="--[no-]skip-private-repositories">
    Skip cloning private repositories
  </definition>
</definitions>


## Global Options

<definitions>
  <definition term="-l --log-level enum">
    Minimum log level.
    **Values:** trace, debug, information, warning, error, critical, none
    **Default:** `information`
  </definition>
  <definition term="-c --config-source enum">
    Override the configuration source: local, remote
    **Values:** local, remote, embedded
  </definition>
  <definition term="--[no-]skip-private-repositories">
    Skip cloning private repositories
  </definition>
</definitions>


## Profile-based mode

Define reusable profiles in `changelog.yml` and invoke by name. This is the recommended approach for release workflows because the filter, output path, and product metadata are all captured in configuration and don't need to be specified on the command line.
```sh
# Bundle using a named profile (version inferred for {lifecycle} placeholder)
docs-builder changelog bundle elasticsearch-release 9.2.0

# Bundle using a profile with a promotion report as the filter source
docs-builder changelog bundle elasticsearch-release 9.2.0 ./promotion-report.html
```

The second positional argument accepts:
- A version string (e.g. `9.2.0`, `9.2.0-beta.1`) — lifecycle is inferred automatically (`ga`, `beta`, `rc`)
- A promotion report URL or file path
- A plain-text URL list file (one fully-qualified GitHub PR or issue URL per line)
- A plain-text path list file (one changelog YAML path per line, ending in `.yaml` or `.yml`)

When your profile uses `{version}` in its output pattern and you also want to filter by a report or list file, pass both arguments (version first, then the filter file).
Example profile in `changelog.yml`:
```yaml
bundle:
  repo: elasticsearch
  owner: elastic
  directory: docs/changelog
  output_directory: docs/releases
  profiles:
    elasticsearch-release:
      products: "elasticsearch {version} {lifecycle}"
      output: "elasticsearch/{version}.yaml"
      output_products: "elasticsearch {version}"
```


## Option-based mode

Supply filter flags directly when you don't have a profile configured or need a one-off bundle.
Exactly one of the following filter flags is required:
- `--all` — include every changelog in the directory
- `--input-products` — match by product, target date, and lifecycle (e.g. `"elasticsearch * *"`)
- `--prs` — filter by PR URLs or a newline-delimited file of PR URLs
- `--issues` — filter by issue URLs or a newline-delimited file of issue URLs
- `--release-version` — fetch PR references from a GitHub release tag (e.g. `v9.2.0` or `latest`)
- `--report` — filter by PRs referenced in a promotion report (URL or local file)
- `--files` — include specific changelog YAML paths, or a newline-delimited path list file

`--force-local` is not a filter. It forces local entry sourcing for the run (equivalent to `bundle.use_local_changelogs: true` without editing config) and is allowed in both option-based and profile-based modes.
```sh
# Bundle all changelogs in docs/changelog/
docs-builder changelog bundle --all --directory docs/changelog

# Bundle changelogs for a specific product release
docs-builder changelog bundle \
  --input-products "elasticsearch 9.2.0 ga" \
  --output docs/releases/9.2.0.yaml

# Bundle from a GitHub release
docs-builder changelog bundle \
  --release-version v9.2.0 \
  --repo elasticsearch \
  --owner elastic

# Bundle an explicit list of changelog files
docs-builder changelog bundle \
  --files "./docs/changelog/a.yaml,./docs/changelog/b.yaml" \
  --output docs/releases/serverless/2026-07-07.yaml \
  --output-products "cloud-serverless 2026-07-07"
```


## Bundles are self-contained

Every bundle embeds the full content of each changelog entry (`title`, `type`, `products`, and so on), plus a `file` block recording the source file name and checksum for provenance. Rendering — via the `{changelog}` directive, `changelog render`, or the CDN pipeline — never reads the original changelog files, so you can clean them up with `docs-builder changelog remove` immediately after bundling.

## CI usage

Pass `--plan` to emit GitHub Actions step outputs (`needs_network`, `needs_github_token`, `output_path`) without generating the bundle. Use this in a planning step to decide whether subsequent steps require a GitHub token or network access.
For full configuration reference, see [Bundle changelogs](https://docs-v3-preview.elastic.dev/elastic/docs-builder/pull/3804/data/release-notes/bundle).

## Product format

The `changelog bundle` command has `--input-products` and `--output-products` options that accept values with the format `"product target lifecycle, ..."` where:
- `product` is the product ID from [products.yml](https://github.com/elastic/docs-builder/blob/main/config/products.yml) (required)
- `target` is the target version or date (optional)
- `lifecycle` exists in [Lifecycle.cs](https://github.com/elastic/docs-builder/blob/main/src/Elastic.Documentation/Lifecycle.cs) (optional)

You can further limit the possible values with the [products](/elastic/docs-builder/pull/3804/data/release-notes/configure-ref#products) and [lifecycles](/elastic/docs-builder/pull/3804/data/release-notes/configure-ref#lifecycles) options in the changelog configuration file.
For example:
- `"kibana 9.2.0 ga"`
- `"cloud-serverless 2025-08-05"`
- `"cloud-enterprise 4.0.3, cloud-hosted 2025-10-31"`

If you use `"* * *"` in the `--input-products` command option or `bundle.profiles.<name>.products` configuration setting, it's equivalent to the `--all` command option.

## Lifecycle inference

The way that lifecycle values are inferred varies between GitHub release profiles and standard profiles.

### GitHub release profiles

For `source: github_release` profiles, the `{lifecycle}` placeholder in `output` and `output_products` is derived from the full release tag name. For example:

| Release tag        | `{version}` | `{lifecycle}` |
|--------------------|-------------|---------------|
| `v1.2.3`           | `1.2.3`     | `ga`          |
| `v1.2.3-beta.1`    | `1.2.3`     | `beta`        |
| `v1.2.3-preview.1` | `1.2.3`     | `preview`     |


### Standard profiles

For standard profiles, `{version}` is copied verbatim from your command argument and `{lifecycle}` is derived from that value. For example:

| Version argument  | `{version}`       | `{lifecycle}` |
|-------------------|-------------------|---------------|
| `9.2.0`           | `9.2.0`           | `ga`          |
| `9.2.0-beta.1`    | `9.2.0-beta.1`    | `beta`        |
| `9.2.0-preview.1` | `9.2.0-preview.1` | `preview`     |
| `2026-07-21`      | `2026-07-21`      | `ga`          |

Profile mode does not accept lifecycle on the command line. For semver and date-based releases alike, set lifecycle in the profile YAML:
- Omit lifecycle from the pattern (for example, `"cloud-serverless {version}"`) to leave the field out of the bundle.
- Use `{lifecycle}` to derive it from the version or date argument (as in the table above).
- Hardcode a lifecycle (for example, `"cloud-serverless {version} ga"` or `"cloud-serverless {version} preview"`) when you need an explicit value. Non-`ga` date-based releases are exceptional and should use a hardcoded lifecycle.

For more information about acceptable product and lifecycle values, go to [Product format](#product-format).

## PR and issue link allowlist

A changelog in a public repository might contain links to pull requests or issues in repositories that should not appear in published documentation.
Set `bundle.link_allow_repos` in `changelog.yml` to an explicit list of `owner/repo` strings. When this key is present (including as an empty list), PR and issue references are filtered at bundle time: only links whose resolved repository is in the list are kept; others are rewritten to `# PRIVATE:` sentinel strings in the bundle YAML.

## Examples


### Bundle by GitHub release

You can use `--release-version` to fetch pull request references directly from GitHub release notes and use them as the bundle filter.
This is equivalent to building a PR list file manually and passing it with `--prs`, but without any file management.
<important>
  Only automated GitHub release notes (the default format or [Release Drafter](https://github.com/release-drafter/release-drafter) format) are supported at this time.
</important>

```sh
docs-builder changelog bundle \
  --release-version v1.34.0 \ 
  --repo apm-agent-dotnet \ 
  --owner elastic 
  --output-products "apm-agent-dotnet 1.34.0 ga" 
```

<note>
  `--release-version` requires a `GITHUB_TOKEN` or `GH_TOKEN` environment variable (or an active `gh` login) to fetch release details from the GitHub API.
</note>

By default all changelogs that match PRs in the GitHub release notes are included in the bundle.
To apply additional filtering by the changelog type, areas, or products, add [rules.bundle](/elastic/docs-builder/pull/3804/data/release-notes/configure-ref#rules-bundle) configuration settings.
<tip>
  If you are not creating changelogs when you create your pull requests, consider the `docs-builder changelog gh-release` command as a one-shot alternative to the `changelog add` and `changelog bundle` commands.
  It parses the release notes, creates one changelog file per pull request found, and creates a `changelog-bundle.yaml` file — all in a single step. Refer to [changelog gh-release](https://docs-v3-preview.elastic.dev/elastic/docs-builder/pull/3804/cli/changelog/gh-release).
</tip>


### Bundle by issues

You can use the `--issues` option to create a bundle of changelogs that relate to those GitHub issues.
Issues can be identified by a full URL (such as `https://github.com/owner/repo/issues/123`), a short format (such as `owner/repo#123`), or just a number (in which case `--owner` and `--repo` are required — or set via `bundle.owner` and `bundle.repo` in the configuration).
```sh
docs-builder changelog bundle --issues "12345,12346" \
  --repo elasticsearch \
  --owner elastic \
  --output-products "elasticsearch 9.2.2 ga"
```

Alternatively, you can specify a path to a newline-delimited file that contains the issue URLS (for example, `--issues /path/to/file.txt`).
In this case, you cannot use short URLs or numbers, each line must have a full URL.
By default all changelogs that match issues in the list are included in the bundle.
To apply additional filtering by the changelog type, areas, or products, add [rules.bundle](/elastic/docs-builder/pull/3804/data/release-notes/configure-ref#rules-bundle) configuration settings.

### Bundle by pull requests

You can use the `--prs` option to create a bundle of the changelogs that relate to those pull requests.
Pull requests can be identified by a full URL (such as `https://github.com/owner/repo/pull/123`), a short format (such as `owner/repo#123`), or just a number.
```sh
docs-builder changelog bundle --prs "108875,135873,136886" \ 
  --repo elasticsearch \ 
  --owner elastic \ 
  --output-products "elasticsearch 9.2.2 ga" 
```

Alternatively, you can specify a path to a newline-delimited file that contains the PR URLS (for example, `--prs /path/to/file.txt`).
In this case, you cannot use short URLs or numbers, each line must have a full URL.
For example:
```txt
https://github.com/elastic/elasticsearch/pull/108875
https://github.com/elastic/elasticsearch/pull/135873
https://github.com/elastic/elasticsearch/pull/136886
https://github.com/elastic/elasticsearch/pull/137126
```

By default all changelogs that match PRs in the list are included in the bundle.
To apply additional filtering by the changelog type, areas, or products, add [rules.bundle](/elastic/docs-builder/pull/3804/data/release-notes/configure-ref#rules-bundle) configuration settings.
If you have changelog files that reference those pull requests, the command creates a file like this:
```yaml
products:
- product: elasticsearch
  target: 9.2.2
  lifecycle: ga
entries:
- file:
    name: 1765507819-fix-ml-calendar-event-update-scalability-issues.yaml
    checksum: 069b59edb14594e0bc3b70365e81626bde730ab7
  type: bug-fix
  title: Fix ML calendar event update scalability issues
  products:
  - product: elasticsearch
    target: 9.2.2
  prs:
  - https://github.com/elastic/elasticsearch/pull/108875
- file:
    name: 1765507798-convert-bytestransportresponse-when-proxying-respo.yaml
    checksum: c6dbd4730bf34dbbc877c16c042e6578dd108b62
  type: bug-fix
  title: Convert BytesTransportResponse when proxying responses
  products:
  - product: elasticsearch
    target: 9.2.2
  prs:
  - https://github.com/elastic/elasticsearch/pull/135873
```


### Bundle by product

You can use the `--input-products` option to create a bundle of changelogs that match the product details.
When using `--input-products`, you must provide all three parts: product, target, and lifecycle.
Each part can be a wildcard (`*`) to match any value.
<tip>
  If you use profile-based bundling, provide this information in the `bundle.profiles.<name>.products` field.
</tip>

```sh
docs-builder changelog bundle \
  --input-products "cloud-serverless 2025-12-02 ga, cloud-serverless 2025-12-06 beta" 
```

You can use wildcards in any of the three parts:
```sh
# Bundle any changelogs that have exact matches for either of these clauses
docs-builder changelog bundle --input-products "cloud-serverless 2025-12-02 ga, elasticsearch 9.3.0 beta"

# Bundle all elasticsearch changelogs regardless of target or lifecycle
docs-builder changelog bundle --input-products "elasticsearch * *"

# Bundle all cloud-serverless 2025-12-02 changelogs with any lifecycle
docs-builder changelog bundle --input-products "cloud-serverless 2025-12-02 *"

# Bundle any cloud-serverless changelogs with target starting with "2025-11-" and "ga" lifecycle
docs-builder changelog bundle --input-products "cloud-serverless 2025-11-* ga"

# Bundle all changelogs (equivalent to --all)
docs-builder changelog bundle --input-products "* * *"
```

If you have changelog files that reference those product details, the command creates a file like this:
```yaml
products: 
- product: cloud-serverless
  target: 2025-12-02
- product: cloud-serverless
  target: 2025-12-06
entries:
- file:
    name: 1765495972-fixes-enrich-and-lookup-join-resolution-based-on-m.yaml
    checksum: 6c3243f56279b1797b5dfff6c02ebf90b9658464
  type: bug-fix
  title: Fixes enrich and lookup join resolution based on mappings
  products:
  - product: cloud-serverless
    target: 2025-12-02
  prs:
  - https://github.com/elastic/elasticsearch/pull/136001
- file:
    name: 1765507778-break-on-fielddata-when-building-global-ordinals.yaml
    checksum: 70d197d96752c05b6595edffe6fe3ba3d055c845
  type: bug-fix
  title: Break on fielddata when building global ordinals
  products:
  - product: cloud-serverless
    target: 2025-12-06
  prs:
  - https://github.com/elastic/elasticsearch/pull/136002
```

<note>
  When a changelog matches multiple `--input-products` filters, it appears only once in the bundle. This deduplication applies even when using `--all` or `--prs`.
</note>


### Bundle by report

You can use `--report` to filter by a promotion report:
```sh
# Extract PRs from a downloaded report and use them as the filter
docs-builder changelog bundle \
  --report ./promotion-report.html \
  --directory ./docs/changelog \
  --output ./docs/releases/bundle.yaml
```

By default all changelogs that match PRs in the promotion report are included in the bundle.
To apply additional filtering by the changelog type, areas, or products, add [rules.bundle](/elastic/docs-builder/pull/3804/data/release-notes/configure-ref#rules-bundle) configuration settings.

### Bundle by file paths

Use `--files` when you know the exact changelog files to include and they may not have `prs` or `issues` metadata.
```sh
docs-builder changelog bundle \
  --files "./docs/changelog/a.yaml,./docs/changelog/b.yaml" \
  --output docs/releases/serverless/2026-07-07.yaml \
  --output-products "cloud-serverless 2026-07-07"
```

You can also pass a newline-delimited path list file:
```sh
docs-builder changelog bundle --files ./docs/temp/changelog_files.txt --output ...
```

In profile mode, pass the same path list as a positional argument:
```sh
docs-builder changelog bundle serverless-release 2026-07-07 ./docs/temp/changelog_files.txt
```

`--files` / path-list selection always reads the named files from disk (local entry sourcing). It does not fetch entries from the CDN. `rules.bundle` still applies after selection.

### Force local entry sourcing

When a repository defaults to CDN entry sourcing, you can use `--force-local` to read changelog YAML files from the local folder.
This option overrides the `bundle.use_local_changelogs` setting in your `changelog.yml` and is useful for ad hoc bundles that include freshly authored local files that are not on the CDN yet.
```sh
docs-builder changelog bundle serverless-release 2026-07-07 ./docs/temp/prs.txt --force-local
```

`--force-local` is allowed in both option-based and profile-based commands.
Path-list / `--files` filters already force local sourcing, so `--force-local` is optional in that case.

### Hide features

You can use the `--hide-features` option to embed feature IDs that should be hidden when the bundle is rendered. This is useful for features that are not yet ready for public documentation.
```sh
docs-builder changelog bundle \
  --input-products "elasticsearch 9.3.0 *" \
  --hide-features "feature:hidden-api,feature:experimental" \ 
  --output /path/to/bundles/9.3.0.yaml
```

The bundle output will include a `hide-features` field:
```yaml
products:
- product: elasticsearch
  target: 9.3.0
hide-features:
  - feature:hidden-api
  - feature:experimental
entries:
- file:
    name: 1765495972-new-feature.yaml
    checksum: 6c3243f56279b1797b5dfff6c02ebf90b9658464
  type: feature
  title: New feature behind a flag
  feature-id: feature:hidden-api
  products:
  - product: elasticsearch
    target: 9.3.0
```

When this bundle is rendered (either via the `changelog render` command or the `{changelog}` directive), changelogs with `feature-id` values matching any of the listed features will be commented out in the output.
<note>
  The `--hide-features` option on the `render` command and the `hide-features` field in bundles are **combined**. If you specify `--hide-features` on both the `bundle` and `render` commands, all specified features are hidden. The `{changelog}` directive automatically reads `hide-features` from all loaded bundles and applies them.
</note>