For AI agents: a documentation index is available at the root level at /llms.txt and /llms-full.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.
      • AstroFully-managed data operations, powered by Apache Airflow.
      • Astro Private CloudRun Airflow-as-a-service in your environment.
      • Professional ServicesExpert Airflow services for your enterprise's success.
    • Tools
      • Cosmos
      • Orbiter
      • CLI
      • AI SDK
      • Agents
      • Blueprint
      • UpdatesThe State of Airflow 2026See the insights from over 5,800 data practitioners in the full report. Download Now ➔
  • Customers
  • Docs
    • Insights
      • Blog
      • Webinars
      • Resource Library
      • Events
    • Education
      • Academy
      • What is Airflow?
  • Pricing
Get Started Free
    • Astro Private Cloud overview
    • Astro Private Cloud features
      • Install overview
      • Install the control plane
      • Install a data plane
      • Install in unified mode
        • Merge yaml configurations
        • Add trusted certificate authorities (CAs)
        • Disable outbound email
        • Trust private certificate authorities
        • Disable managing quotas and limitranges
      • Log in to Astro Private Cloud

Product

  • Platform Overview
  • Astro
  • Astro Observe
  • Astro Private Cloud
  • Security & Trust
  • Pricing

Tools & Services

  • Cosmos
  • Docs
  • Professional Services
  • Product Updates

Use Cases

  • AI Ops
  • Data Observability
  • ETL/ELT
  • ML Ops
  • Operational Analytics
  • All Use Cases

Industries

  • Financial Services
  • Gaming
  • Retail
  • Manufacturing
  • Healthcare
  • All Industries

Resources

  • Academy
  • eBooks & Guides
  • Blog
  • Webinars
  • Events
  • The Data Flowcast Podcast
  • All Resources

Airflow

  • What is Airflow
  • Airflow on Astro
  • Airflow 3.0
  • Airflow Upgrades
  • Airflow Use Cases
  • Airflow 2.x End of Life

Company

  • Our Story
  • Customers
  • Newsroom
  • Careers
  • Contact

Support

  • Knowledge Base
  • Status
  • Contact Support
GitHubYouTubeLinkedInx
  • Legal
  • Privacy
  • Terms of Service
  • Consent Preferences

  • Do Not Sell or Share My Personal information
  • Limit the Use Of My Sensitive Personal Information

Apache Airflow®, Airflow, and the Airflow logo are trademarks of the Apache Software Foundation. Copyright © Astronomer 2026. All rights reserved.

LogoLogo
Install Astro Private CloudCustomize your installation

Merge YAML configurations

Edit this page
Built with

When merging YAML configurations into values.yaml, you can merge manually or with a tool of your choosing.

You can use the following merge_yaml.py script to merge YAML excerpts into values.yaml automatically. This script requires both Python and the ruamel.yaml package, which you can install using pip install ruamel.yaml. To run the program, ensure that merge_yaml.py, values.yaml, and the yaml file that contains the configuration you want to add are all in your project directory. Then, run:

$python merge_yaml.py values-to-merge.yaml values.yaml
1#!/usr/bin/env python
2"""
3Backup destination file and merge YAML contents of src into dest.
4
5By default creates backups, overwrites destination, and clobbers lists.
6
7Usage:
8 merge_yaml.py src dest [--create-backup=True] [--dry-run] [--show-stacktrace=False] [--merge-lists=True] [--help]
9"""
10
11import argparse
12import os
13import shutil
14from datetime import datetime
15import sys
16from pathlib import Path
17
18# Check Python version
19if sys.version_info < (3, 0):
20 print("Error: This script requires Python 3.0 or greater.")
21 sys.exit(2)
22
23# Try importing ruamel.yaml
24try:
25 from ruamel.yaml import YAML
26except ImportError:
27 print(
28 "Error: ruamel.yaml is not installed. Please install it using 'pip install ruamel.yaml'"
29 )
30 sys.exit(2)
31
32yaml = YAML()
33
34def deep_merge(d1, d2, **kwargs):
35 """Deep merges dictionary d2 into dictionary d1."""
36 merge_lists = kwargs.get("merge_lists")
37 for key, value in d2.items():
38 if key in d1:
39 if isinstance(d1[key], dict) and isinstance(value, dict):
40 deep_merge(d1[key], value, **kwargs)
41 elif merge_lists and isinstance(d1[key], list) and isinstance(value, list):
42 d1[key].extend(value)
43 else:
44 d1[key] = value
45 else:
46 d1[key] = value
47 return d1
48
49def load_yaml_file(filename):
50 """Load YAML data from a file."""
51 if not os.path.exists(filename):
52 return {}
53 with open(filename, "r") as file:
54 return yaml.load(file)
55
56def save_yaml_file(filename, data):
57 """Save YAML data to a file."""
58 with open(filename, "w") as file:
59 yaml.dump(data, file)
60
61def create_backup(filename):
62 """Create a timestamped backup of the file."""
63 # create a directory called backups relative to the filename
64 backup_dir = filename.parent / "yaml_backups"
65 try:
66 backup_dir.mkdir(exist_ok=True)
67 except Exception as e:
68 print(
69 f"Error: Could not create backup directory {backup_dir}. Check your file-permissions or use --no-create-backup to skip creating a backup."
70 )
71 exit(2)
72
73 timestamp = datetime.now().strftime("%y%m%d%H%M%S")
74 backup_filename = backup_dir / f"{filename.name}.{timestamp}.bak"
75 shutil.copyfile(filename, backup_filename)
76 print(f"Backup created: {backup_filename}")
77
78def main():
79 parser = argparse.ArgumentParser(
80 description="Deep merge YAML contents of src into dest."
81 )
82 parser.add_argument("src", type=Path, help="Source filename")
83 parser.add_argument("dest", type=Path, help="Destination filename")
84 parser.add_argument(
85 "--create-backup",
86 type=bool,
87 default=True,
88 help="Create a backup of the destination file before merging",
89 )
90 parser.add_argument(
91 "--dry-run",
92 action="store_true",
93 help="Print to stdout only, do not write to the destination file",
94 )
95 # add a argument for showing the stack trace on yaml parse errors
96 parser.add_argument(
97 "--show-stacktrace",
98 action="store_true",
99 help="Show stack trace on yaml parse errors",
100 )
101 # add an argument to clobber lists
102 parser.add_argument(
103 "--merge-lists",
104 action="store_true",
105 help="Merge list items instead of clobbering",
106 default=False,
107 )
108
109 args = parser.parse_args()
110
111 src_filename = args.src.resolve().expanduser()
112 dest_filename = args.dest.resolve().expanduser()
113
114 # make sure both files exist
115 if not src_filename.exists():
116 print(f"Error: {args.src} does not exist")
117 exit(2)
118
119 if not dest_filename.exists():
120 print(f"Error: {args.dest} does not exist")
121 exit(2)
122
123 try:
124 src_data = load_yaml_file(src_filename)
125 except Exception as e:
126 print(
127 f"Error: {args.src} is not a valid YAML file. Run with --show-stacktrace to see the error."
128 )
129 if args.show_stacktrace:
130 raise e
131 exit(2)
132 try:
133 dest_data = load_yaml_file(dest_filename)
134 except Exception as e:
135 print(
136 f"Error: {args.dest} is not a valid YAML file. Run with --show-stacktrace to see the error."
137 )
138 if args.show_stacktrace:
139 raise e
140 exit(2)
141
142 if args.create_backup and not args.dry_run:
143 create_backup(dest_filename)
144
145 src_data = load_yaml_file(args.src)
146 dest_data = load_yaml_file(args.dest)
147
148 # if dest_data is empty, just copy src_data to dest_data
149 if not dest_data:
150 if not args.dry_run:
151 save_yaml_file(args.dest, src_data)
152 else:
153 merged_data = deep_merge(dest_data, src_data, merge_lists=args.merge_lists)
154 if not args.dry_run:
155 save_yaml_file(args.dest, merged_data)
156 print(f"Merged data from {args.src} into {args.dest}")
157 else:
158 yaml.dump(merged_data, sys.stdout)
159
160if __name__ == "__main__":
161 main()