PageSourceSearch

https://www.astronomer.io/product/

html astronomer.io collected 2026-10-01 10:26:31 UTC 128,530 bytes, 1,186 lines download raw bytes

1<!DOCTYPE html><html lang="en"> <head>
1<script>
vendor: 455 bytes, lines 1-11
1
2      (function (w, d, s, l, i) {
3        w[l] = w[l] || [];
4        w[l].push({ "gtm.start": new Date().getTime(), event: "gtm.js" });
5        var f = d.getElementsByTagName(s)[0],
6          j = d.createElement(s),
7          dl = l != "dataLayer" ? "&l=" + l : "";
8        j.async = true;
9        j.src = "https://www.googletagmanager.com/gtm.js?id=" + i + dl;
10        f.parentNode.insertBefore(j, f);
11      })(window, document, "script", "dataLayer", "
11GTM-WCJNSWTS
vendor: 8 bytes, lines 11-12
11");
12    
12</script>
12<!-- 
12<script is:inline>
13      // The Termly consent tag enables gtag URL passthrough, which appends _gl
14      // to same-site links so the client id survives without cookies. gtag
15      // reads the value into memory at container load, so the parameter can be
16      // dropped from the address bar afterwards without losing the handoff.
17      (function () {
18        var stripped = false;
19        function stripLinkerParam() {
20          if (stripped) return;
21          stripped = true;
22          var url = new URL(window.location.href);
23          if (!url.searchParams.has("_gl")) return;
24          url.searchParams.delete("_gl");
25          window.history.replaceState(null, "", url.toString());
26        }
27        window.dataLayer = window.dataLayer || [];
28        var push = window.dataLayer.push;
29        window.dataLayer.push = function () {
30          for (var i = 0; i < arguments.length; i++) {
31            if (arguments[i] && arguments[i].event === "gtm.load") {
32              window.setTimeout(stripLinkerParam, 0);
33            }
34          }
35          return push.apply(this, arguments);
36        };
37        window.setTimeout(stripLinkerParam, 4000);
38      })();
39    </script>
39 -->
39<script>(function(){const apiKey = "phc_BZVoUAXORGgUxvJAwR75nn5Nl0kze20qf1Qs21giUUO";
40const apiHost = "https://us.i.posthog.com";
41
42  // -- 1. PostHog stub -------------------------------------------------------
43  // Creates window.posthog as a lightweight queue. Any capture() / identify()
44  // calls made before posthog.init() are held here. They are replayed by the
45  // real library once init() is called (consent granted), or silently dropped
46  // when the page unloads (consent never granted / declined).
47  //
48  // The e.__SV guard also prevents the stub being re-initialised on Astro
49  // View Transition navigations where this is:inline script re-executes.
50  !(function (t, e) {
51    var o, n, p, r;
52    e.__SV ||
53      ((window.posthog = e),
54      (e._i = []),
55      (e.init = function (i, s, a) {
56        function g(t, e) {
57          var o = e.split(".");
58          (2 == o.length && ((t = t[o[0]]), (e = o[1])),
59            (t[e] = function () {
60              t.push([e].concat(Array.prototype.slice.call(arguments, 0)));
61            }));
62        }
63        (((p = t.createElement("script")).type = "text/javascript"),
64          (p.crossOrigin = "anonymous"),
65          (p.async = !0),
66          (p.src = s.api_host + "/static/array.js"),
67          (r = t.getElementsByTagName("script")[0]).parentNode.insertBefore(
68            p,
69            r,
70          ));
71        var u = e;
72        for (
73          void 0 !== a ? (u = e[a] = []) : (a = "posthog"),
74            u.people = u.people || [],
75            u.toString = function (t) {
76              var e = "posthog";
77              return (
78                "posthog" !== a && (e += "." + a),
79                t || (e += " (stub)"),
80                e
81              );
82            },
83            u.people.toString = function () {
84              return u.toString(1) + ".people (stub)";
85            },
86            o =
87              "capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys getNextSurveyStep onSessionId".split(
88                " ",
89              ),
90            n = 0;
91          n < o.length;
92          n++
93        )
94          g(u, o[n]);
95        e._i.push([i, s, a]);
96      }),
97      (e.__SV = 1));
98  })(document, window.posthog || []);
99
100  // -- 2. PostHog initialisation + Termly consent wiring --------------------
101  // PostHog is always initialised with cookieless_mode "on_reject" so that
102  // users who decline or never engage with the Termly banner are still counted
103  // via a privacy-preserving server-side hash (no cookies, no localStorage).
104  // Termly is loaded via GTM (async), so window.Termly is never available when
105  // this script runs. We poll until it appears, then check the stored state and
106  // subscribe to changes to drive opt_in_capturing / opt_out_capturing.
107  //
108  // window.__phConsentBound guards against Astro View Transitions re-running
109  // this is:inline script on every client-side navigation, which would create
110  // duplicate polls and call posthog.init() on an already-running instance.
111  if (apiKey && !window.__phConsentBound) {
112    window.__phConsentBound = true;
113    (function () {
114      // optedIn tri-state: null = pending (SDK initialised, awaiting Termly
115      // consent decision); true = analytics consent granted (full
116      // localStorage+cookie tracking); false = declined or never engaged
117      // (cookieless server-hash tracking via on_reject mode).
118      var optedIn = null;
119
120      // Guard 1 — Drop events missing distinct_id.
121      //
122      // PostHog ingestion rejects any event whose distinct_id is absent or
123      // empty at the capture_validation pipeline step.  This can happen in a
124      // brief race window during SDK initialisation when the SDK's
125      // persistence has been cleared but the new anonymous device ID has not
126      // yet been written back.  enableExceptionAutocapture makes the window
127      // especially relevant: the window.onerror handler is registered early in
128      // the SDK's init sequence, so a JS exception thrown by a GTM tag, chat
129      // widget, or browser extension during that window produces a $exception
130      // event with no distinct_id that then fails ingestion.  Dropping such
131      // events here prevents the ingestion error regardless of which code path
132      // produced the empty identity.
133      function dropEventsWithoutDistinctId(event) {
134        if (!event) return null;
135        var distinctId = event.properties && event.properties.distinct_id;
136        if (
137          distinctId === null ||
138          distinctId === undefined ||
139          distinctId === ""
140        ) {
141          return null;
142        }
143        return event;
144      }
145
146      // Guard 2 — Drop noisy, non-actionable JSON-parse exceptions before they
147      // reach PostHog error tracking. Both variants are thrown by third-party
148      // code (browser extensions / privacy add-ons, or a GTM-injected tag that
149      // calls JSON.parse on a raw Google Ads gclid) and surface unhandled
150      // through window.onerror. None originate from our own code — they land
151      // on every page type, including the third-party-proxied /docs/* — so
152      // there is nothing to fix in-app; we filter them here to stop the
153      // Signals inbox filling with unfixable, non-actionable reports:
154      //
155      //   - Firefox: `SyntaxError: JSON.parse: ...` with no stack frames. With
156      //     nothing to group on, every occurrence mints a brand-new issue.
157      //   - WebKit (Safari / iOS): `SyntaxError: JSON Parse error: Unexpected
158      //     identifier ...` carrying a single synthetic frame whose filename is
159      //     the page URL. These group into one stable issue that keeps going
160      //     quiet and reopening weeks later, pulling someone in to re-triage.
161      //
162      // The WebKit variant carries a frame, so we can't simply require zero
163      // frames. To avoid swallowing genuine parse bugs in our own inline
164      // scripts, we require its single frame to point at the document URL
165      // itself — an external bundled script would report its own .js filename.
166      function onlyFrameIsDocument(frames) {
167        if (frames.length !== 1) return false;
168        var filename = frames[0] && (frames[0].filename || frames[0].abs_path);
169        if (!filename) return false;
170        var stripQuery = function (url) {
171          // The offending URL carries the gclid as a query param, so compare on
172          // origin + path only (both sides stripped of query string and hash).
173          return String(url).split("?")[0].split("#")[0];
174        };
175        return stripQuery(filename) === stripQuery(window.location.href);
176      }
177      function dropExtensionJsonParseErrors(event) {
178        if (!event || event.event !== "$exception") return event;
179        var list = (event.properties && event.properties.$exception_list) || [];
180        var allNoise =
181          list.length > 0 &&
182          list.every(function (ex) {
183            if (!ex || ex.type !== "SyntaxError") return false;
184            var value = (ex && ex.value) || "";
185            var handled = ex && ex.mechanism && ex.mechanism.handled;
186            if (handled !== false) return false;
187            var frames = (ex && ex.stacktrace && ex.stacktrace.frames) || [];
188
189            // Firefox: JSON.parse noise arrives with no stack frames at all.
190            if (value.indexOf("JSON.parse:") !== -1 && frames.length === 0) {
191              return true;
192            }
193
194            // WebKit (Safari / iOS): one synthetic frame that must point at the
195            // document itself — see onlyFrameIsDocument.
196            if (
197              value.indexOf("JSON Parse error: Unexpected identifier") !== -1 &&
198              onlyFrameIsDocument(frames)
199            ) {
200              return true;
201            }
202
203            return false;
204          });
205        return allNoise ? null : event;
206      }
207
208      // Compose both guards into a single before_send handler.
209      function beforeSend(event) {
210        if (dropEventsWithoutDistinctId(event) === null) return null;
211        return dropExtensionJsonParseErrors(event);
212      }
213
214      // PostHog is always initialised immediately with cookieless_mode
215      // "on_reject". In this mode the SDK starts in a *pending* state: no
216      // cookies, no localStorage writes, no event capture — until one of:
217      //   opt_in_capturing()  -> full tracking with localStorage+cookie
218      //   opt_out_capturing() -> cookieless server-hash tracking (privacy-safe)
219      // Termly drives which path is taken; see handleConsentState below.
220      function initPostHog() {
221        posthog.init(apiKey, {
222          api_host: apiHost || "https://us.i.posthog.com",
223          cookieless_mode: "on_reject",
224          persistence: "localStorage+cookie", // used only after opt_in_capturing()
225          defaults: "2026-01-30",
226          before_send: beforeSend,
227          enableExceptionAutocapture: true,
228          loaded: function (ph) {
229            // The loaded callback is the authoritative place to apply consent
230            // state to the real SDK, because stub method calls queued before
231            // the SDK loads are NOT reliably replayed into on_reject mode's
232            // consent state machine. Explicitly set the correct state here
233            // for all three cases:
234            //
235            //   optedIn === true  → analytics accepted before SDK loaded;
236            //                       call opt_in_capturing() on the real SDK.
237            //   optedIn === false → declined/pending before SDK loaded;
238            //                       call opt_out_capturing() (cookieless hash).
239            //   optedIn === null  → Termly hasn't resolved yet; PostHog stays
240            //                       in pending state until handleConsentState
241            //                       fires on the real SDK directly.
242            if (optedIn === true) {
243              ph.opt_in_capturing();
244            } else if (optedIn === false) {
245              ph.opt_out_capturing();
246            }
247          },
248        });
249      }
250
251      // Called on first load (getConsentState) and on every preference change
252      // (Termly.on "consent"). Handles all scenarios:
253      //   - New visitor, banner pending  -> cookieless hash (on_reject default)
254      //   - New visitor accepts          -> opt_in: full localStorage+cookie
255      //   - Returning visitor (accepted) -> opt_in (consent in Termly cookie)
256      //   - Visitor declines             -> opt_out: cookieless hash tracking
257      //   - Consent withdrawn            -> opt_out: cookieless hash tracking
258      //   - Consent re-granted           -> opt_in (only when previously opted out)
259      //   - Other category changes       ->
259 no-op (analytics state unchanged)
260      //
261      // NOTE: Termly.on("consent", handler) fires with payload
262      //   {categories, consentState, cookies, uuid}
263      // whereas getConsentState() returns
264      //   {analytics, advertising, ...} directly.
265      // We normalise both shapes here so one function handles both call sites.
266      function handleConsentState(state) {
267        var consentState =
268          state && state.consentState ? state.consentState : state;
269        if (consentState && consentState.analytics) {
270          // Analytics consent granted -> full tracking with cookies.
271          // Guard prevents spurious opt_in_capturing() calls when other Termly
272          // categories change while analytics consent remains granted.
273          if (optedIn !== true) {
274            optedIn = true;
275            posthog.opt_in_capturing();
276          }
277        } else {
278          // Analytics declined, never engaged, or Termly state unavailable ->
279          // cookieless server-hash tracking. opt_out_capturing() halts
280          // cookie/localStorage use; no stored identity is retained.
281          if (optedIn !== false) {
282            optedIn = false;
283            posthog.opt_out_capturing();
284          }
285        }
286      }
287
288      function attachTermly() {
289        // Synchronously check stored consent (handles returning visitors whose
290        // preference cookie is already set when Termly loads).
291        handleConsentState(window.Termly.getConsentState());
292        // Subscribe to banner resolution and preference-centre changes.
293        if (typeof window.Termly.on === "function") {
294          window.Termly.on("consent", handleConsentState);
295        }
296      }
297
298      // Initialise PostHog immediately with cookieless_mode "on_reject".
299      // The SDK starts in pending state (no cookies, no capture) and waits
300      // for an explicit opt_in_capturing() or opt_out_capturing() call, which
301      // Termly drives below. Initialising here (rather than inside
302      // attachTermly) ensures the SDK is ready the moment Termly resolves,
303      // and means users who decline or never engage are still counted via the
304      // privacy-preserving server-side hash.
305      initPostHog();
306
307      // Termly is loaded via GTM (async) so it will never be present when
308      // this script runs. Poll for window.Termly for up to 10 s.
309      // On timeout: fall back to cookieless hash tracking so users whose
310      // Termly never loads (ad-blocker, network error) are still counted.
311      // 50 ms x 200 attempts = 10 s ceiling.
312      var attempts = 0;
313      var poll = setInterval(function () {
314        if (
315          window.Termly &&
316          typeof window.Termly.getConsentState === "function"
317        ) {
318          clearInterval(poll);
319          attachTermly();
320        } else if (++attempts >= 200) {
321          clearInterval(poll);
322          // Termly never loaded — enable cookieless hash tracking so these
323          // visitors are still counted without storing any personal data.
324          if (optedIn === null) {
325            optedIn = false;
326            posthog.opt_out_capturing();
327          }
328        }
329      }, 50);
330    })();
331  }
332})();</script>
332<meta name="theme-color" content="#2b215b"><meta name="zd-site-verification" content="7t9sz8mmjc4h40v4nj39ra"><!-- Preload critical fonts (self-hosted, same-origin) --><link rel="preload" href="/fonts/league-gothic/league-gothic-latin.woff" as="font" type="font/woff" crossorigin> <link rel="preload" href="/fonts/roboto/roboto-normal-latin.woff2" as="font" type="font/woff2" crossorigin> <!-- Roboto Condensed — used by CaseStudyHero and article headings --> <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto+Condensed:wght@300;400;500;600;700&display=swap"> <!-- Resource Hints --> <!-- preconnect pre-warms DNS + TCP + TLS for the heaviest third parties --> <link rel="preconnect" href="https://www.googletagmanager.com"> <link rel="preconnect" href="https://app.termly.io" crossorigin> <!-- go.astronomer.io is Marketo's Forms2 endpoint; pre-warming TCP+TLS reduces
333     form load latency, particularly on campaign-blast days when Marketo is slow. --> <link rel="preconnect" href="https://go.astronomer.io"> <!-- dns-prefetch as fallback for browsers that don't support preconnect, and for lower-priority origins --> <link rel="dns-prefetch" href="https://www.googletagmanager.com"> <link rel="dns-prefetch" href="https://app.termly.io"> <link rel="dns-prefetch" href="https://go.astronomer.io"> <!-- Global Metadata --> <meta name="google-site-verification" content="uI5eT7_d5Q5FjDUVa_VUxgeZxuBrYWiPMCLqZUOjrcA"> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <link rel="icon" type="image/svg+xml" href="/favicon.svg"> <meta name="generator" content="Astro v7.3.3"> <link rel="sitemap" href="/sitemap-index.xml"> <!-- Canonical URL --> <link rel="canonical" href="https://www.astronomer.io/product/">  <!-- Hreflang Alternate Links for SEO -->  <!-- Primary Meta Tags --> <title>Astro: Enterprise-Grade Airflow for Scalable Data Pipelines</title> <meta name="title" content="Astro: Enterprise-Grade Airflow for Scalable Data Pipelines"> <meta name="description" content="Astro: Enterprise-grade Apache Airflow® for scalable, secure, and reliable data pipelines. Reduce downtime, improve data security, and boost ROI."> <meta name="robots" content="all"> <!-- Content ID --> <meta name="contentID" content="Page-product"> <meta name="contentType" content="Page" data-pagefind-filter="category[content]">  <!-- Open Graph / Facebook --> <meta property="og:type" content="website"> <meta property="og:url" content="https://www.astronomer.io/product/"> <meta property="og:title" content="Astro: Enterprise-Grade Airflow for Scalable Data Pipelines"> <meta property="og:description" content="Astro: Enterprise-grade Apache Airflow® for scalable, secure, and reliable data pipelines. Reduce downtime, improve data security, and boost ROI."> <meta property="og:image" content="/images/featured-image-homepage.jpg"> <!-- Twitter --> <meta property="twitter:card" content="summary_large_image"> <meta property="twitter:url" content="https://www.astronomer.io/product/"> <meta property="twitter:title" content="Astro: Enterprise-Grade Airflow for Scalable Data Pipelines"> <meta property="twitter:description" content="Astro: Enterprise-grade Apache Airflow® for scalable, secure, and reliable data pipelines. Reduce downtime, improve data security, and boost ROI."> <meta property="twitter:image" content="/images/featured-image-homepage.jpg"> <meta property="twitter:site" content="@astronomerio"> <meta property="twitter:creator" content="The Astronomer Team"> 
333<script type="application/ld+json">{
334  "@context": "https://schema.org",
335  "@type": "WebPage",
336  "mainEntityOfPage": {
337    "@type": "WebPage",
338    "@id": "https://www.astronomer.io/product/"
339  },
340  "headline": "Astro: Enterprise-Grade Airflow for Scalable Data Pipelines",
341  "description": "Astro: Enterprise-grade Apache Airflow® for scalable, secure, and reliable data pipelines. Reduce downtime, improve data security, and boost ROI.",
342  "image": {
343    "@type": "ImageObject",
344    "url": "undefined",
345    "width": "",
346    "height": ""
347  },
348  "author": {
349    "@type": "Organization",
350    "name": "Astronomer"
351  },
352  "publisher": {
353    "@type": "Organization",
354    "name": "Astronomer",
355    "logo": {
356      "@type": "ImageObject",
357      "url": "https://www.astronomer.io/logo.svg",
358      "width": "400",
359      "height": "41"
360    }
361  },
362  "datePublished": "",
363  "@graph": [
364    {
365      "@type": "Organization",
366      "@id": "https://www.astronomer.io/#organization",
367      "name": "Astronomer",
368      "url": "https://www.astronomer.io",
369      "logo": {
370        "@type": "ImageObject",
371        "url": "https://www.astronomer.io/logo.svg",
372        "width": "400",
373        "height": "41"
374      },
375      "sameAs": [
376        "https://github.com/astronomer",
377        "https://twitter.com/astronomerio",
378        "https://www.linkedin.com/company/astronomer/",
379        "https://www.facebook.com/astronomerio",
380        "https://www.youtube.com/c/Astronomer",
381        "https://www.instagram.com/astronomerdata/"
382      ],
383      "contactPoint": [
384        {
385          "@type": "ContactPoint",
386          "url": "https://www.astronomer.io/contact/",
387          "email": "[email protected]",
388          "contactType": "company contact"
389        },
390        {
391          "@type": "ContactPoint",
392          "url": "https://support.astronomer.io/",
393          "email": "[email protected]",
394          "contactType": "customer support"
395        },
396        {
397          "@type": "ContactPoint",
398          "url": "https://www.astronomer.io/contact/",
399          "email": "[email protected]",
400          "contactType": "sales"
401        }
402      ],
403      "description": "Astronomer empowers data teams to enhance their data availability with Astro, a modern data orchestration platform powered by Apache Airflow. Astro enables companies to place Airflow at the core of their data operations, providing ease of use, scalability, and enterprise-grade security to ensure the reliable delivery of mission-critical data pipelines.",
404      "address": {
405        "@type": "PostalAddress",
406        "streetAddress": "54 W. 21st St., Suite 1100",
407        "addressLocality": "New York",
408        "addressRegion": "NY",
409        "postalCode": "10010",
410        "addressCountry": "US"
411      }
412    },
413    {
414      "@type": "WebSite",
415      "@id": "https://www.astronomer.io/",
416      "url": "https://www.astronomer.io/",
417      "name": "Astronomer",
418      "publisher": { "@id": "https://www.astronomer.io/#organization" }
419    }
420  ]
421}</script>
421<link rel="preload" href="/pagefind/pagefind-component-ui.css" as="style" onload="this.onload=null;this.rel='stylesheet'"><noscript><link href="/pagefind/pagefind-component-ui.css" rel="stylesheet"></noscript>
421<script src="/pagefind/pagefind-component-ui.js" type="module"></script>
421<link rel="stylesheet" href="/_astro/BaseLayout.COSHb4xh.css"><style>.acds-hero{--acds-hero-height:100vh;--acds-hero-max-height:700px;--acds-hero-padding-top:214px;--acds-hero-padding-bottom:136px;height:var(--acds-hero-height);min-height:min-content;max-height:max-content;padding-top:var(--acds-hero-padding-top);padding-bottom:var(--acds-hero-padding-bottom);background:var(--background,#fff);color:var(--textColor,var(--moonshot-700));height:max-content;position:relative;overflow:clip}.acds-hero__content{--container-width:1210px;z-index:1;height:max-content;padding-bottom:var(--acds-hero-content-padding-bottom);opacity:1;position:relative}@keyframes hero-content-fadeIn{0%{opacity:0}to{opacity:1}}
422.acds-hero[data-astro-cid-pugaqhis]{background:var(--background,#fff);color:var(--textColor,var(--moonshot-700));height:max-content}.acds-hero__content[data-astro-cid-pugaqhis]{z-index:1;position:relative}.acds-hero__stars-bg[data-astro-cid-pugaqhis]{z-index:0;width:1245px;min-width:1245px;height:516px;margin:0 auto;position:absolute;top:0;left:0;right:0}.acds-hero__stars-bg-2[data-astro-cid-pugaqhis]{left:unset;width:auto;margin:0;right:calc(50% - 1200px)}
423</style><link rel="stylesheet" href="/_astro/SignupForm.60h7V7Es.css"><style>.page-section{background-color:var(--new-moon-95,#111121);color:#fff}.page-section+.page-section{padding-top:60px}.page-content-banner{--card-border-radius:5px}.page-content-banner__content{justify-content:space-evenly}.page-content-banner a{color:var(--new-moon-30);justify-self:end}.page-content-banner__title h2{font-size:20px;font-style:normal;font-weight:600;line-height:1.4}.page-stats-content{background:var(--new-moon-05);border-radius:20px;padding:108px 58px}.page-stat{--card-border-radius:5px;--card-background-color:var(--new-moon-10);--card-border-color:transparent;--card-text-color:var(--new-moon-70);text-align:center;flex-direction:column;justify-content:center;align-self:stretch;align-items:center;gap:10px;min-height:197px;display:flex}.page-stat__number{color:var(--new-moon-80,#343247);font-family:var(--theme-font-family-heading);text-transform:uppercase;font-size:72px;font-style:normal;font-weight:400;line-height:48px;transition:color .3s}.page-stat:hover{--card-background-color:var(--new-moon-20)}.page-stat:hover .page-stat__number{color:var(--purple-60)}.page-feature-stack__items{padding-top:38px;padding-bottom:60px}.page-feature-stack__item{--card-background-color:var(--new-moon-95);border-top:0;border-left:0;border-right:0;padding:48px 24px}.page-feature-stack__item:last-of-type{border-bottom:0}.page-feature-stack__item-text{--row-flow-margin:10px;max-width:384px}.page-feature-stack__item-link{margin-top:38px;display:block}#trusted{padding-top:120px}.acds-hero__image{margin-block:4rem}#trusted .acds-body-lg{margin-top:1rem}.acds-hero .acds-tag img{display:none}.otto-dot{background:var(--gold-40);border:1px solid #ffb32d40;border-radius:50%;width:7.5px;height:7.5px;animation:2s infinite pulse;display:inline-block}@keyframes pulse{0%,to{opacity:1}50%{opacity:.5}}
424.acds-calloutBox{text-align:center;border:1px solid var(--Purple-50,#a067fb);backdrop-filter:blur(2px);max-width:870px;color:var(--new-moon-10);background:#34324799;border-radius:5px;flex-direction:column;flex-shrink:0;justify-content:center;align-self:stretch;align-items:center;gap:28px;margin-inline:auto;padding:48px;display:flex}.acds-calloutBox__eyebrow{color:var(--purple-50,#a067fb);text-transform:uppercase;letter-spacing:.1em}.acds-calloutBox__title{color:var(--white)}.acds-calloutBox__title-highlight{color:var(--purple-50,#a067fb)}.acds-calloutBox__desc{max-width:740px}.acds-calloutBox__secondary-desc{color:var(--new-moon-30,#d0c9c2);max-width:740px}.acds-calloutBox .acds-button.purple{--button-background-color:var(--purple-50,#a067fb);--button-border-color:var(--purple-50,#a067fb);--button-background-color-hover:var(--purple-60,#872ded);--button-border-color-hover:var(--purple-60,#872ded);border-radius:10px}
425</style><link rel="stylesheet" href="/_astro/NebulaCallToAction.B2NgiwXI.css"><style>.acds-featureSection{--row-flow-margin:42px}.acds-featureSection,.acds-featureSection__children{z-index:1;position:relative}.acds-featureSection--bg-texture-image{top:calc(anchor(top) - 10px);z-index:0;pointer-events:none;width:1580px;max-width:1580px;height:726px;position:fixed;left:50%;transform:translate(-50%)}.acds-featureSection--bg-texture-image[src="/images/bg-textures/radial-bg-texture.svg"],.acds-featureSection--bg-texture-image[src="/images/bg-textures/bg-texture-architecture.svg"]{top:calc(anchor(top) + 10px);right:calc(anchor(right));z-index:0;pointer-events:none;width:1340px;height:1556px}.acds-featureSection__fixedTitle .acds-featureSection__fixedTitleContent{position:relative;top:10px}@media screen and (width<=979px){.page-cards .acds-featureSection__children .grid-container{grid-template-columns:1fr 1fr}.acds-card.acds-featureCard{max-width:100%}}@media screen and (width<=500px){.page-cards .acds-featureSection__children .grid-container{grid-template-columns:1fr}}
426</style><link rel="stylesheet" href="/_astro/Sections.InTo9sM7.css">
426<link rel="stylesheet" href="/_astro/FeatureTabs.Dj5CD7MT.css"><style>.acds-product-card{--card-border-radius:5px}.acds-product-card[data-theme-color=teal]{--card-border-color:var(--teal-50)}.acds-product-card[data-theme-color=teal] a,.acds-product-card[data-theme-color=teal] .acds-eyebrow{color:var(--teal-50)}.acds-product-card[data-theme-color=green]{--card-border-color:var(--green-50)}.acds-product-card[data-theme-color=green] a,.acds-product-card[data-theme-color=green] .acds-eyebrow{color:var(--green-50)}.acds-product-card[data-theme-color=red]{--card-border-color:var(--red-50)}.acds-product-card[data-theme-color=red] a,.acds-product-card[data-theme-color=red] .acds-eyebrow{color:var(--red-50)}.acds-product-card__items{flex-wrap:wrap;gap:24px;display:flex}.acds-product-card-one-image .acds-product-card__items{grid-template-columns:1fr 1fr;display:grid}.acds-product-card__item{--row-flow-margin:10px;--card-background-color:transparent;--card-border-color:transparent;flex:272px;padding:24px}.acds-product-card__item:hover,.acds-product-card__item:focus{background-color:var(--new-moon-95)}.acds-product-card__item-description{color:var(--new-moon-10,#f0ece5)}.acds-product-card__image{background:var(--new-moon-70,#555261);width:222px;height:222px}.acds-product-card-one-image .acds-product-card__image{background:0 0;width:100%;height:643px}.acds-product-card__link{margin-top:50px;display:block}.acds-product-card-one-image{min-height:max-content;padding-top:80px;padding-right:0;overflow:hidden}@media screen and (width<=980px){.acds-product-card__text{--row-flow-margin:10px}.acds-product-card__link{margin-top:1rem}.acds-product-card-one-image .acds-product-card__items{grid-template-columns:1fr}}
427.acds-faqsblock{--acds-faqsblock-background:var(--new-moon-90);background:var(--acds-faqsblock-background);flex-wrap:wrap;justify-content:center;align-items:flex-start;gap:165px;padding:80px 120px;display:flex;position:relative}.acds-faqsblock__title:before{content:"";stroke-dashoffset:6px;align-self:anchor-center;z-index:0;position-anchor:--acds-faqsblock__title;border-top:3px dashed #555261;width:1000%;position:absolute;left:-10rem;right:-10rem}.acds-faqsblock__title{anchor-name:--acds-faqsblock__title;anchor-scope:--acds-faqsblock__title}.acds-faqsblock__heading{background:var(--acds-faqsblock-background);z-index:2;font-family:var(--theme-font-family-heading), "League Gothic", "Albert Sans", sans-serif;letter-spacing:.02em;text-transform:uppercase;color:var(--white);margin:0;padding-inline:20px;font-size:60px;font-weight:400;line-height:68px;position:relative}.acds-faqsblock__description{color:var(--new-moon-10);margin-top:16px;font-family:Roboto,Inter,sans-serif;font-size:16px;line-height:1.75}.acds-faqsblock__faqs{flex:632px;max-width:632px}@media (width<=1024px){.acds-faqsblock{gap:32px;padding:60px 40px}.acds-faqsblock__title{flex:none}.acds-faqsblock__faqs{max-width:100%}}@media (width<=768px){.acds-faqsblock{flex-direction:column;gap:24px;padding:40px 24px}.acds-faqsblock__heading{font-size:48px;line-height:56px}}.page-faqs{padding-top:80px;padding-bottom:80px;overflow:hidden}.page-faqs .page-section__content{padding:0}
428.acds-accordion{background:var(--new-moon-95);border:2px solid var(--new-moon-70);box-sizing:border-box;margin-bottom:-4px;padding:20px;transition:background .3s;position:relative}.acds-accordion[open]{background:var(--new-moon-90)}.acds-accordion summary:after{display:none!important}.acds-accordion__summary::-webkit-details-marker{display:none}.acds-accordion__summary{cursor:pointer;color:var(--white);outline:none;justify-content:space-between;align-items:flex-start;gap:16px;margin:0;padding:0;list-style:none;display:flex}.acds-accordion__summary:focus-visible{outline:3px solid var(--purple-40);outline-offset:2px}.acds-accordion__question{letter-spacing:0;color:var(--white);font-variation-settings:"wdth" 75;flex:1;font-family:Roboto,sans-serif;font-size:20px;font-weight:600;line-height:28px}.acds-accordion__arrow{width:16px;height:16px;color:var(--white);flex-shrink:0;margin-top:6px;transition:transform .3s}.acds-accordion[open]>.acds-accordion__summary .acds-accordion__arrow{transform:rotate(180deg)}.acds-accordion__details-wrapper{box-sizing:border-box;overflow:hidden}.acds-accordion[data-closing] .acds-accordion__details-wrapper{display:block!important}.acds-accordion__details{letter-spacing:0;color:var(--new-moon-10);box-sizing:border-box;padding-top:10px;font-family:Roboto Mono,monospace;font-size:12px;font-weight:400;line-height:20px}.acds-accordion__details p{margin:0}.acds-accordion__details p+p{margin-top:12px}.acds-accordion__details p:last-child{margin-bottom:0}.acds-accordion__details a{color:var(--gold-40);text-decoration:underline}.acds-accordion__details a:hover{color:var(--gold-30)}.acds-accordion__details ul,.acds-accordion__details ol{margin:12px 0;padding-left:24px}.acds-accordion__details li{margin:4px 0}.acds-accordion__details code{background:var(--new-moon-95);border-radius:3px;padding:2px 6px;font-family:JetBrains Mono,monospace;font-size:11px}.acds-accordion__details pre{background:var(--new-moon-95);border-radius:5px;margin:12px 0;padding:12px;overflow-x:auto}.acds-accordion__details pre code{background:0 0;padding:0}@media (width<=768px){.acds-accordion{padding:16px}.acds-accordion__question{font-size:18px;line-height:26px}.acds-accordion__details{font-size:11px;line-height:18px}}
429.grid-container{gap:var(--grid-container-gap,1rem);align-items:var(--align-items,stretch);justify-content:var(--justify-content,start);display:grid}@media screen and (width>=980px){.grid-container{--grid-container-gap:var(--gap,3rem);grid-template-columns:var(--columnsManual,repeat(var(--columns,1), var(--columnWidth,1fr)))}}.grid-container.align-stretch{align-items:stretch}.grid-container.align-start{align-items:start}.grid-container.align-end{align-items:end}.grid-container.align-center{align-items:center}
429.grid-container.align-baseline{align-items:baseline}.grid-container.justify-start{justify-content:start}.grid-container.justify-end{justify-content:end}.grid-container.justify-center{justify-content:center}.grid-container.justify-stretch{justify-content:stretch}.grid-container.justify-space-around{justify-content:space-around}.grid-container.justify-space-between{justify-content:space-between}.grid-container.justify-space-evenly{justify-content:space-evenly}
430</style><link rel="stylesheet" href="/_astro/RuntimeArchitecture.DQtxwxV4.css"><link rel="stylesheet" href="/_astro/LogoGrid.OYsBc7YR.css"><link rel="stylesheet" href="/_astro/Tabs.BqkEiG_j.css"></head> <body>
vendor: 69 bytes, line 430
430 <noscript> <iframe src="https://www.googletagmanager.com/ns.html?id=
430GTM-WCJNSWTS
vendor: 84 bytes, line 430
430" height="0" width="0" style="display:none;visibility:hidden"></iframe> </noscript> 
430<div class="header-wrapper"> <style>astro-island,astro-slot,astro-static-slot{display:contents}</style>
430<script>(()=>{var e=async t=>{await(await t())()};(self.Astro||(self.Astro={})).load=e;window.dispatchEvent(new Event("astro:load"));})();</script>
430<script>(()=>{var g=Object.defineProperty;var w=(a,s,c)=>s in a?g(a,s,{enumerable:!0,configurable:!0,writable:!0,value:c}):a[s]=c;var l=(a,s,c)=>w(a,typeof s!="symbol"?s+"":s,c);var E=new Set(["__proto__","constructor","prototype"]);{let a={0:t=>y(t),1:t=>c(t),2:t=>new RegExp(t),3:t=>new Date(t),4:t=>new Map(c(t)),5:t=>new Set(c(t)),6:t=>BigInt(t),7:t=>new URL(t),8:t=>new Uint8Array(t),9:t=>new Uint16Array(t),10:t=>new Uint32Array(t),11:t=>Number.POSITIVE_INFINITY*t},s=t=>{let[p,e]=t;return p in a?a[p](e):void 0},c=t=>t.map(s),y=t=>typeof t!="object"||t===null?t:Object.fromEntries(Object.entries(t).map(([p,e])=>[p,s(e)]));class f extends HTMLElement{constructor(){super(...arguments);l(this,"Component");l(this,"hydrator");l(this,"hydrate",async()=>{var b;if(!this.hydrator||!this.isConnected)return;let e=(b=this.parentElement)==null?void 0:b.closest("astro-island[ssr]");if(e){e.addEventListener("astro:hydrate",this.hydrate,{once:!0});return}let r=this.querySelectorAll("astro-slot"),n={},d=this.querySelectorAll("template[data-astro-template]");for(let o of d){let i=o.closest(this.tagName);i!=null&&i.isSameNode(this)&&(n[o.getAttribute("data-astro-template")||"default"]=o.innerHTML,o.remove())}for(let o of r){let i=o.closest(this.tagName);i!=null&&i.isSameNode(this)&&(n[o.getAttribute("name")||"default"]=o.innerHTML)}let u;try{u=this.hasAttribute("props")?y(JSON.parse(this.getAttribute("props"))):{}}catch(o){let i=this.getAttribute("component-url")||"<unknown>",v=this.getAttribute("component-export");throw v&&(i+=` (export ${v})`),console.error(`[hydrate] Error parsing props for component ${i}`,this.getAttribute("props"),o),o}let h;await this.hydrator(this)(this.Component,u,n,{client:this.getAttribute("client")}),this.removeAttribute("ssr"),this.dispatchEvent(new CustomEvent("astro:hydrate"))});l(this,"unmount",()=>{this.isConnected||this.dispatchEvent(new CustomEvent("astro:unmount"))})}disconnectedCallback(){document.removeEventListener("astro:after-swap",this.unmount),document.addEventListener("astro:after-swap",this.unmount,{once:!0})}connectedCallback(){if(!this.hasAttribute("await-children")||document.readyState==="interactive"||document.readyState==="complete")this.childrenConnectedCallback();else{let e=()=>{document.removeEventListener("DOMContentLoaded",e),r.disconnect(),this.childrenConnectedCallback()},r=new MutationObserver(()=>{var n;((n=this.lastChild)==null?void 0:n.nodeType)===Node.COMMENT_NODE&&this.lastChild.nodeValue==="astro:end"&&(this.lastChild.remove(),e())});r.observe(this,{childList:!0}),document.addEventListener("DOMContentLoaded",e)}}async childrenConnectedCallback(){let e=this.getAttribute("before-hydration-url");e&&await import(e),this.start()}getRetryImportUrl(e){let r=new URL(e,document.baseURI);return r.searchParams.set("astro-retry",Date.now().toString()),r.toString()}async importWithRetry(e){try{return await import(e)}catch(r){return await new Promise(n=>setTimeout(n,1e3)),import(this.getRetryImportUrl(e))}}handleHydrationError(e){let r=this.getAttribute("component-url"),n=new CustomEvent("astro:hydration-error",{cancelable:!0,bubbles:!0,composed:!0,detail:{error:e,componentUrl:r}});this.dispatchEvent(n)&&console.error(`[astro-island] Error hydrating ${r}`,e)}async start(){let e=JSON.parse(this.getAttribute("opts")),r=this.getAttribute("client");if(Astro[r]===void 0){window.addEventListener(`astro:${r}`,()=>this.start(),{once:!0});return}try{await Astro[r](async()=>{let n=this.getAttribute("renderer-url");try{let[d,{default:u}]=await Promise.all([this.importWithRetry(this.getAttribute("component-url")),n?this.importWithRetry(n):Promise.resolve({default:()=>()=>{}})]),h=this.getAttribute("component-export")||"default";if(h.includes(".")){this.Component=d;for(let m of h.split(".")){if(E.has(m)||!this.Component||typeof this.Component!="object"&&typeof this.Component!="function"||!Object.hasOwn(this.Component,m))throw new Error(`Invalid component export path: ${h}`);this.Component=this.Component[m]}}else{if(E.has(h))throw new Error(`Invalid component export path: ${h}`);this.Component=d[h]}return this.hydrator=u,this.hydrate}catch(d){return this.handleHydrationError(d),()=>{}}},e,this)}catch(n){this.handleHydrationError(n)}}attributeChangedCallback(){this.hydrate()}}l(f,"observedAttributes",["props"]),customElements.get("astro-island")||customElements.define("astro-island",f)}})();</script>
430<astro-island uid="ZI7B7P" prefix="r8" component-url="/_astro/Header.BVeGOihb.js?dpl=6abd1c0e8e511d0008ca4db3" component-export="default" renderer-url="/_astro/client.CgkIogCC.js?dpl=6abd1c0e8e511d0008ca4db3" props="{&quot;theme&quot;:[0],&quot;promoBanner&quot;:[0],&quot;hidePromoBanner&quot;:[0,false]}" ssr client="load" opts="{&quot;name&quot;:&quot;Header&quot;,&quot;value&quot;:true}" await-children><header class="header" data-theme="dark"><div class="container flex-container justify-between headerWrapper"><a href="/" class="logo" aria-label="Go to Home Page"><span class="logoTitle">Astronomer</span><span class="logoImg"></span></a><button class="menuToggle" id="menuToggle" aria-label="Open Navigation Menu"><div class="hamburger hamburgerCollapse"><div class="hamburgerBox"><div class="hamburgerInner"></div></div></div></button><nav aria-label="Main Navigation" class="headerNav"><ul class="headerNavList list-reset"><li class="dropdown"><button class="block dropdownTitle">Product<svg width="14" height="15" viewBox="0 0 14 15" class="dropdown-caret" xmlns="http://www.w3.org/2000/svg"><path d="M3.74141 5.75L10.2584 5.75C10.3738 5.75002 10.4865 5.78425 10.5824 5.84835C10.6783 5.91245 10.7531 6.00354 10.7972 6.11012C10.8414 6.21669 10.8529 6.33396 10.8304 6.4471C10.8079 6.56024 10.7524 6.66417 10.6708 6.74575L7.41233 10.0042C7.30294 10.1136 7.15459 10.175 6.99991 10.175C6.84523 10.175 6.69689 10.1136 6.5875 10.0042L3.329 6.74575C3.24744 6.66417 3.1919 6.56024 3.16941 6.4471C3.14691 6.33396 3.15846 6.21669 3.2026 6.11012C3.24674 6.00354 3.32149 5.91245 3.41739 5.84835C3.5133 5.78425 3.62606 5.75002 3.74141 5.75Z"></path></svg></button><ul class="dropdownMenu list-reset is-two-column" id="product-dropdown"><li class="child hasChildren list-reset"><ul class="grandchildren  list-reset product
431                        "><li class="grandchild-section-title"><span class="topTitle">choose your deployment</span></li><li class="grandchild  grandchild--hasDescription "><a href="/product/" class="link"><span class="icon-wrapper"><img src="/icons/nav/rocket-lunch (3).svg" data-gold-icon="/icons/nav/rocket-lunch (3)--gold.svg" width="24" height="24" loading="lazy" alt="" class="icon-default"/><img src="/icons/nav/rocket-lunch (3)--gold.svg" width="24" height="24" loading="lazy" alt="" class="icon-gold"/></span><span class="grandchild-text"><span class="linkTitle ">Astro</span><span class="linkDesc">Fully-managed orchestration platform, powered by Apache Airflow.</span></span></a></li><li class="grandchild  grandchild--hasDescription "><a href="/product/astro-private-cloud/" class="link"><span class="icon-wrapper"><img src="/icons/nav/fi-br-cloud.svg" data-gold-icon="/icons/nav/fi-br-cloud--gold.svg" width="24" height="24" loading="lazy" alt="" class="icon-default"/><img src="/icons/nav/fi-br-cloud--gold.svg" width="24" height="24" loading="lazy" alt="" class="icon-gold"/></span><span class="grandchild-text"><span class="linkTitle ">Astro Private Cloud</span><span class="linkDesc">Run Airflow-as-a-service in your environment.</span></span></a></li><li class="grandchild-section-title"><span class="topTitle">agentic data engineering</span></li><li class="grandchild  grandchild--hasDescription isHighlighted"><a href="/otto/" class="link"><span class="icon-wrapper"><img src="/icons/nav/otto.svg" data-gold-icon="/icons/nav/otto--gold.svg" width="39" height="40" loading="lazy" alt="" class="icon-default"/><img src="/icons/nav/otto--gold.svg" width="39" height="40" loading="lazy" alt="" class="icon-gold"/></span><span class="grandchild-text"><span class="linkTitle ">Introducing Otto</span><span class="linkDesc">Your data engineering agent built for Airflow.</span></span></a></li></ul></li><li class="child hasChildren list-reset"><div class="link hasChildren"><span class="linkTitle topTitle">Tools</span></div><ul class="grandchildren two-column list-reset tools
432                        "><li class="grandchild   "><a href="/cosmos/" class="link"><span class="icon-wrapper"><img src="/icons/nav/dbt.svg" data-gold-icon="/icons/nav/dbt--gold.svg" width="12" height="12" loading="lazy" alt="" class="icon-default"/><img src="/icons/nav/dbt--gold.svg" width="12" height="12" loading="lazy" alt="" class="icon-gold"/></span><span class="grandchild-text"><span class="linkTitle ">Cosmos</span></span></a></li><li class="grandchild   "><a href="/docs/astro/cli/overview" class="link"><span class="icon-wrapper"><img src="/icons/nav/terminal square.svg" data-gold-icon="/icons/nav/terminal square--gold.svg" width="12" height="12" loading="lazy" alt="" class="icon-default"/><img src="/icons/nav/terminal square--gold.svg" width="12" height="12" loading="lazy" alt="" class="icon-gold"/></span><span class="grandchild-text"><span class="linkTitle ">CLI</span></span></a></li><li class="grandchild   "><a href="https://github.com/astronomer/agents" class="link" target="_blank"><span class="icon-wrapper"><img src="/icons/nav/fi-br-cube.svg" data-gold-icon="/icons/nav/fi-br-cube--gold.svg" width="12" height="12" loading="lazy" alt="" class="icon-default"/><img src="/icons/nav/fi-br-cube--gold.svg" width="12" height="12" loading="lazy" alt="" class="icon-gold"/></span><span class="grandchild-text"><span class="linkTitle ">Agents</span></span></a></li><li class="grandchild   "><a href="https://github.com/astronomer/blueprint" class="link" target="_blank"><span class="icon-wrapper"><img src="/icons/nav/fi-br-cube.svg" data-gold-icon="/icons/nav/fi-br-cube--gold.svg" width="12" height="12" loading="lazy" alt="" class="icon-default"/><img src="/icons/nav/fi-br-cube--gold.svg" width="12" height="12" loading="lazy" alt="" class="icon-gold"/></span><span class="grandchild-text"><span class="linkTitle ">Blueprint</span></span></a></li><li class="grandchild isCTA grandchild--hasDescription "><a href="/airflow/state-of-airflow/" class="link"><span class="grandchild-text"><span class="linkTitle topTitle">Updates</span><span class="isCTA--title">The State of Airflow 2026</span><span class="linkDesc">See the insights from over 5,800 data practitioners in the full report. <span class="nav-item-ctaLinkText">Download Now ➔</span></span></span></a></li></ul></li></ul></li><li class="dropdown"><a href="/customers/" class="block dropdownTitle">Customers</a></li><li class="dropdown"><a href="/docs/" class="block dropdownTitle">Docs</a></li><li class="dropdown"><button class="block dropdownTitle">Resources<svg width="14" height="15" viewBox="0 0 14 15" class="dropdown-caret" xmlns="http://www.w3.org/2000/svg"><path d="M3.74141 5.75L10.2584 5.75C10.3738 5.75002 10.4865 5.78425 10.5824 5.84835C10.6783 5.91245 10.7531 6.00354 10.7972 6.11012C10.8414 6.21669 10.8529 6.33396 10.8304 6.4471C10.8079 6.56024 10.7524 6.66417 10.6708 6.74575L7.41233 10.
4320042C7.30294 10.1136 7.15459 10.175 6.99991 10.175C6.84523 10.175 6.69689 10.1136 6.5875 10.0042L3.329 6.74575C3.24744 6.66417 3.1919 6.56024 3.16941 6.4471C3.14691 6.33396 3.15846 6.21669 3.2026 6.11012C3.24674 6.00354 3.32149 5.91245 3.41739 5.84835C3.5133 5.78425 3.62606 5.75002 3.74141 5.75Z"></path></svg></button><ul class="dropdownMenu list-reset " id="resources-dropdown"><li class="child hasChildren list-reset"><div class="link hasChildren"><span class="linkTitle topTitle">Insights</span></div><ul class="grandchildren two-column list-reset insights
433                        "><li class="grandchild   "><a href="/blog/" class="link"><span class="icon-wrapper"><img src="/icons/nav/blog.svg" data-gold-icon="/icons/nav/blog--gold.svg" width="12" height="12" loading="lazy" alt="" class="icon-default"/><img src="/icons/nav/blog--gold.svg" width="12" height="12" loading="lazy" alt="" class="icon-gold"/></span><span class="grandchild-text"><span class="linkTitle ">Blog</span></span></a></li><li class="grandchild   "><a href="/events/webinars/" class="link"><span class="icon-wrapper"><img src="/icons/nav/play-alt.svg" data-gold-icon="/icons/nav/play-alt--gold.svg" width="12" height="12" loading="lazy" alt="" class="icon-default"/><img src="/icons/nav/play-alt--gold.svg" width="12" height="12" loading="lazy" alt="" class="icon-gold"/></span><span class="grandchild-text"><span class="linkTitle ">Webinars</span></span></a></li><li class="grandchild   "><a href="/resources/" class="link"><span class="icon-wrapper"><img src="/icons/nav/book-open-cover.svg" data-gold-icon="/icons/nav/book-open-cover--gold.svg" width="12" height="12" loading="lazy" alt="" class="icon-default"/><img src="/icons/nav/book-open-cover--gold.svg" width="12" height="12" loading="lazy" alt="" class="icon-gold"/></span><span class="grandchild-text"><span class="linkTitle ">Resource Library</span></span></a></li><li class="grandchild   "><a href="/events/" class="link"><span class="icon-wrapper"><img src="/icons/nav/calendar-days.svg" data-gold-icon="/icons/nav/calendar-days--gold.svg" width="12" height="12" loading="lazy" alt="" class="icon-default"/><img src="/icons/nav/calendar-days--gold.svg" width="12" height="12" loading="lazy" alt="" class="icon-gold"/></span><span class="grandchild-text"><span class="linkTitle ">Events</span></span></a></li></ul></li><li class="child hasChildren list-reset"><div class="link hasChildren"><span class="linkTitle topTitle">Education</span></div><ul class="grandchildren two-column list-reset education
434                        "><li class="grandchild   "><a href="https://academy.astronomer.io/" class="link" target="_blank"><span class="icon-wrapper"><img src="/icons/nav/academy.svg" data-gold-icon="/icons/nav/academy--gold.svg" width="12" height="12" loading="lazy" alt="" class="icon-default"/><img src="/icons/nav/academy--gold.svg" width="12" height="12" loading="lazy" alt="" class="icon-gold"/></span><span class="grandchild-text"><span class="linkTitle ">Academy</span></span></a></li><li class="grandchild   "><a href="/airflow/" class="link"><span class="icon-wrapper"><img src="/icons/nav/airflow.svg" data-gold-icon="/icons/nav/airflow--gold.svg" width="12" height="12" loading="lazy" alt="" class="icon-default"/><img src="/icons/nav/airflow--gold.svg" width="12" height="12" loading="lazy" alt="" class="icon-gold"/></span><span class="grandchild-text"><span class="linkTitle ">What is Airflow?</span></span></a></li></ul></li></ul></li><li class="dropdown"><button class="block dropdownTitle">Airflow<svg width="14" height="15" viewBox="0 0 14 15" class="dropdown-caret" xmlns="http://www.w3.org/2000/svg"><path d="M3.74141 5.75L10.2584 5.75C10.3738 5.75002 10.4865 5.78425 10.5824 5.84835C10.6783 5.91245 10.7531 6.00354 10.7972 6.11012C10.8414 6.21669 10.8529 6.33396 10.8304 6.4471C10.8079 6.56024 10.7524 6.66417 10.6708 6.74575L7.41233 10.0042C7.30294 10.1136 7.15459 10.175 6.99991 10.175C6.84523 10.175 6.69689 10.1136 6.5875 10.0042L3.329 6.74575C3.24744 6.66417 3.1919 6.56024 3.16941 6.4471C3.14691 6.33396 3.15846 6.21669 3.2026 6.11012C3.24674 6.00354 3.32149 5.91245 3.41739 5.84835C3.5133 5.78425 3.62606 5.75002 3.74141 5.75Z"></path></svg></button><ul class="dropdownMenu list-reset " id="airflow-dropdown"><li class="child hasChildren list-reset"><ul class="grandchildren  list-reset 
435                        "><li class="grandchild   "><a href="/airflow/" class="link"><span class="grandchild-text"><span class="linkTitle ">What is Airflow?</span></span></a></li><li class="grandchild   "><a href="/airflow/3/" class="link"><span class="grandchild-text"><span class="linkTitle ">Airflow 3</span></span></a></li><li class="grandchild   "><a href="/astro-vs-apache-airflow-oss/" class="link"><span class="grandchild-text"><span class="linkTitle ">Astro vs. Apache Airflow OSS</span></span></a></li><li class="grandchild   ">
435<a href="/airflow/use-cases/" class="link"><span class="grandchild-text"><span class="linkTitle ">Airflow Use Cases</span></span></a></li><li class="grandchild   "><a href="/airflow/security/" class="link"><span class="grandchild-text"><span class="linkTitle ">Airflow Security</span></span></a></li></ul></li></ul></li><li class="dropdown"><a href="/pricing/" class="block dropdownTitle">Pricing</a></li></ul><div class="flex-container buttons justify-center"><button class="search-button" aria-label="Search"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M15.7656 14.5469L12.3594 11.1406C13.3281 9.95312 13.875 8.48438 13.875 6.9375C13.875 5.10938 13.1562 3.39062 11.8594 2.09375C10.5625 0.796875 8.83594 0.078125 7.00781 0.078125C5.17969 0.078125 3.45312 0.796875 2.15625 2.09375C0.859375 3.39062 0.140625 5.10938 0.140625 6.9375C0.140625 8.76562 0.859375 10.4844 2.15625 11.7812C3.45312 13.0781 5.17188 13.7969 7 13.7969C8.54688 13.7969 10.0156 13.25 11.2031 12.2812L14.6094 15.6875C14.625 15.7031 14.6437 15.7156 14.6643 15.7243C14.6849 15.733 14.707 15.7377 14.7293 15.7381C14.7515 15.7385 14.7738 15.7346 14.7947 15.7266C14.8156 15.7187 14.8348 15.7068 14.8511 15.6917C14.8673 15.6765 14.8803 15.6583 14.8894 15.6381C14.8984 15.618 14.9034 15.5962 14.9039 15.5741C14.9045 15.5519 14.9007 15.5299 14.8927 15.5094C14.8847 15.4888 14.8727 15.4701 14.8574 15.4543L15.7656 14.5469ZM10.7031 10.625C9.6875 11.6406 8.38281 12.2031 7 12.2031C5.61719 12.2031 4.3125 11.6406 3.29688 10.625C2.28125 9.60938 1.71875 8.30469 1.71875 6.92188C1.71875 5.53906 2.28125 4.23438 3.29688 3.21875C4.3125 2.20312 5.61719 1.64062 7 1.64062C8.38281 1.64062 9.6875 2.20312 10.7031 3.21875C11.7188 4.23438 12.2812 5.53906 12.2812 6.92188C12.2812 8.30469 11.7188 9.60938 10.7031 10.625Z" fill="white"></path></svg></button><a href="https://cloud.astronomer.io/" class="link login-link">Log In</a><a class="acds-button secondary" href="/book-a-demo/">
435Book a Demo</a><a class="acds-button" href="/lp/signup/">Get Started Free</a></div></nav></div></header><!--astro:end--></astro-island> </div>  <main data-pagefind-body>  <div class="acds-hero" style="--background: var(--new-moon-95, #111121);;--textColor: #fff;" data-astro-cid-pugaqhis>  <div class="acds-hero__content" style="--background: var(--new-moon-95, #111121);;--textColor: #fff;" data-astro-cid-pugaqhis> <div class="container acds-container text-center" style="--container-width:910px"> <div class="acds-hero__content row-flow"> <div class="acds-hero__text row-flow"> <a class="acds-tag flex-container text-center justify-center align-center" id="page-hero-tag" style="background:#18131A;color:#EFB34C;max-width:max-content;margin-inline:auto;gap:6px;border:1px solid #EFB34C" href="/otto/"> <img src="/icons/nav/otto--gold.svg" alt=""> <span "><div class='otto-dot'></div> Meet otto: the agent built for airflow</span> </a> <h1 class="acds-h1">Build, run, and observe your data pipelines.</h1> <p class="acds-body-xl">Astro is the unified orchestration platform for Apache Airflow®. Develop faster, scale reliably, and monitor everything in one place.</p> </div> <div class="acds-hero__buttons flex-container justify-center align-center"> <a href="/lp/signup/" class="acds-button fill"> Get Started Free </a><a href="/book-a-demo/" class="acds-button secondary"> Book a Demo </a> </div> </div> </div> </div> <div class="acds-hero__image container text-left" style="--container-width:910px;"> <a href="/product-tour/" style="display: block; position: relative; width: 100%;"> <img src="https://c.navattic.com/nv_static/61c0bf17635d069b816406e59ee453d64ea81f622309491126c5db365d79bd78" alt="Product Demo" style="width: 100%; height: 100%; object-fit: cover; border: none;"> <div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background: rgba(0, 0, 0, 0.7); color: white; padding: 12px 24px; border-radius: 8px; font-weight: 600;">
436Explore Astro
437</div> </a> </div><div class="acds-hero__logos container" style="--container-width:1212px;"> <div class="logo-grid-wrapper"><div class="logo-grid"><div class="logo-grid__item"><img src="/images/customers/home/notion.svg" alt="Notion" loading="lazy"/></div><div class="logo-grid__item"><img src="/images/customers/home/wynn-resorts.svg" alt="Wynn Resorts" loading="lazy"/></div><div class="logo-grid__item"><img src="/images/customers/home/molson-coors.svg" alt="Molson Coors" loading="lazy"/></div><div class="logo-grid__item"><img src="/images/customers/home/together-ai.svg" alt="together.ai" loading="lazy"/></div><div class="logo-grid__item"><img src="/images/customers/home/t.rowe price.svg" alt="T.Rowe Price" loading="lazy"/></div><div class="logo-grid__item"><img src="/images/customers/home/molson coors.svg" alt="Molson Coors" loading="lazy"/></div><div class="logo-grid__item"><img src="/images/customers/home/merck.svg" alt="Merck" loading="lazy"/></div></div></div> </div> </div> 
437<script>(()=>{var l=(n,t)=>{let i=async()=>{await(await n())()},e=typeof t.value=="object"?t.value:void 0,s={timeout:e==null?void 0:e.timeout};"requestIdleCallback"in window?window.requestIdleCallback(i,s):setTimeout(i,s.timeout||200)};(self.Astro||(self.Astro={})).idle=l;window.dispatchEvent(new Event("astro:idle"));})();</script>
437<astro-island uid="15o2AY" prefix="r6" component-url="/_astro/Sections.DsdE9-vS.js?dpl=6abd1c0e8e511d0008ca4db3" component-export="default" renderer-url="/_astro/client.CgkIogCC.js?dpl=6abd1c0e8e511d0008ca4db3" props="{&quot;sections&quot;:[1,[[0,{&quot;id&quot;:[0,&quot;top&quot;],&quot;type&quot;:[0,&quot;titleBlock&quot;],&quot;title&quot;:[0,&quot;One place to manage the complete data pipeline lifecycle.&quot;],&quot;description&quot;:[0,&quot;Astro brings development, execution, and monitoring together so your team spends less time on infrastructure and more time shipping.&quot;],&quot;titleAlignment&quot;:[0,&quot;center&quot;]}],[0,{&quot;id&quot;:[0,&quot;otto-banner&quot;],&quot;type&quot;:[0,&quot;contentBanner&quot;],&quot;noTopTitle&quot;:[0,true],&quot;title&quot;:[0,&quot;Meet Otto, your data engineering agent&quot;],&quot;description&quot;:[0,&quot;Accelerate every part of your workflow with Otto. Author Dags, review pull requests, investigate production failures, or scope your next upgrade. Otto has the context to act, not just advise, with knowledge of your task logs, connections, and run history, plus the Airflow expertise to know what to do with it.&quot;],&quot;component&quot;:[0,&quot;OttoIntroPrompt&quot;],&quot;link&quot;:[0,{&quot;text&quot;:[0,&quot;Learn more about Otto ➔&quot;],&quot;href&quot;:[0,&quot;/product/otto/&quot;]}]}],[0,{&quot;id&quot;:[0,&quot;build&quot;],&quot;type&quot;:[0,&quot;productCard&quot;],&quot;eyebrow&quot;:[0,&quot;Build&quot;],&quot;noTopTitle&quot;:[0,true],&quot;oneImage&quot;:[0,true],&quot;title&quot;:[0,&quot;Ship production-ready pipelines in minutes.&quot;],&quot;description&quot;:[0,&quot;Astro&#39;s development toolkit covers your entire workflow with AI-assisted coding, flexible testing environments, automated CI/CD, and centralized configuration management.&quot;],&quot;link&quot;:[0,{&quot;text&quot;:[0,&quot;Explore Build features ➔&quot;],&quot;href&quot;:[0,&quot;/product/features#build&quot;]}],&quot;themeColor&quot;:[0,&quot;teal&quot;],&quot;image&quot;:[0,{&quot;src&quot;:[0,&quot;/images/product/build.svg&quot;],&quot;alt&quot;:[0,&quot;&quot;]}],&quot;items&quot;:[1,[[0,{&quot;title&quot;:[0,&quot;Astro IDE&quot;],&quot;description&quot;:[0,&quot;Browser-based editor with context-aware AI that generates production-ready Airflow code. Test and validate Dags instantly, then deploy with one click. No local setup required.&quot;],&quot;image&quot;:[0,{&quot;src&quot;:[0,&quot;&quot;],&quot;alt&quot;:[0,&quot;&quot;]}]}],[0,{&quot;title&quot;:[0,&quot;Astro CLI&quot;],&quot;description&quot;:[0,&quot;Run a complete local Airflow environment to build and test Dags with full control, then deploy to Astro with a single command.&quot;],&quot;image&quot;:[0,{&quot;src&quot;:[0,&quot;&quot;],&quot;alt&quot;:[0,&quot;&quot;]}]}],[0,{&quot;title&quot;:[0,&quot;Astro Terraform Provider&quot;],&quot;description&quot;:[0,&quot;Manage Astro infrastructure as code with Terraform. Provision workspaces, deployments, and clusters using version-controlled configurations. API access also available.&quot;],&quot;image&quot;:[0,{&quot;src&quot;:[0,&quot;&quot;],&quot;alt&quot;:[0,&quot;&quot;]}]}],[0,{&quot;title&quot;:[0,&quot;&lt;span style=&#39;text-transform:lowercase !important&#39;&gt;dbt&lt;/span&gt; Orchestration&quot;],&quot;description&quot;:[0,&quot;Native integration that turns dbt projects into Dags with model-level visibility.&quot;],&quot;image&quot;:[0,{&quot;src&quot;:[0,&quot;&quot;],&quot;alt&quot;:[0,&quot;&quot;]}]}]]]}],[0,{&quot;id&quot;:[0,&quot;run&quot;],&quot;type&quot;:[0,&quot;productCard&quot;],&quot;noTopTitle&quot;:[0,true],&quot;oneImage&quot;:[0,true],&quot;eyebrow&quot;:[0,&quot;Run&quot;],&quot;title&quot;:[0,&quot;Scale to any workload without managing infrastructure.&quot;],&quot;description&quot;:[0,&quot;The Astro engine delivers 2x the performance of other Airflow solutions. Auto-scaling, high availability, and multi-cloud deployment, all made easy for you.&quot;],&quot;link&quot;:[0,{&quot;text&quot;:[0,&quot;Explore Run features ➔&quot;],&quot;href&quot;:[0,&quot;/product/features#run&quot;]}],&quot;
437themeColor&quot;:[0,&quot;green&quot;],&quot;image&quot;:[0,{&quot;src&quot;:[0,&quot;/images/product/run.svg&quot;],&quot;alt&quot;:[0,&quot;&quot;]}],&quot;items&quot;:[1,[[0,{&quot;title&quot;:[0,&quot;Elastic Auto-Scaling&quot;],&quot;description&quot;:[0,&quot;Workers that scale up and down based on task queue depth. Pay only for what you use.&quot;],&quot;image&quot;:[0,{&quot;src&quot;:[0,&quot;&quot;],&quot;alt&quot;:[0,&quot;&quot;]}]}],[0,{&quot;title&quot;:[0,&quot;Disaster Recovery&quot;],&quot;description&quot;:[0,&quot;One-click cross-region failover with underlying data replication handled automatically.&quot;],&quot;image&quot;:[0,{&quot;src&quot;:[0,&quot;&quot;],&quot;alt&quot;:[0,&quot;&quot;]}]}],[0,{&quot;title&quot;:[0,&quot;Remote Execution&quot;],&quot;description&quot;:[0,&quot;Run sensitive workloads in your own environment and dedicated hardware. All while maintaining centralized orchestration and observability in Astro.&quot;],&quot;image&quot;:[0,{&quot;src&quot;:[0,&quot;&quot;],&quot;alt&quot;:[0,&quot;&quot;]}]}],[0,{&quot;title&quot;:[0,&quot;High Availability&quot;],&quot;description&quot;:[0,&quot;Multi-AZ deployments with automatic failover. 99.5% uptime SLA.&quot;],&quot;image&quot;:[0,{&quot;src&quot;:[0,&quot;&quot;],&quot;alt&quot;:[0,&quot;&quot;]}]}]]]}],[0,{&quot;id&quot;:[0,&quot;observe&quot;],&quot;type&quot;:[0,&quot;productCard&quot;],&quot;noTopTitle&quot;:[0,true],&quot;oneImage&quot;:[0,true],&quot;eyebrow&quot;:[0,&quot;Observe&quot;],&quot;title&quot;:[0,&quot;Detect issues before they impact downstream systems.&quot;],&quot;description&quot;:[0,&quot;Real-time lineage, SLA monitoring, proactive alerting, and AI-powered RCA, all built into the orchestration layer, not bolted on as a separate tool.&quot;],&quot;link&quot;:[0,{&quot;text&quot;:[0,&quot;Explore Observe features ➔&quot;],&quot;href&quot;:[0,&quot;/product/features#observe&quot;]}],&quot;image&quot;:[0,{&quot;src&quot;:[0,&quot;/images/product/observe.svg&quot;],&quot;alt&quot;:[0,&quot;&quot;]}],&quot;themeColor&quot;:[0,&quot;red&quot;],&quot;items&quot;:[1,[[0,{&quot;title&quot;:[0,&quot;Pipeline Lineage&quot;],&quot;description&quot;:[0,&quot;Trace upstream/downstream dependencies across Dags, tables, and teams.&quot;],&quot;image&quot;:[0,{&quot;src&quot;:[0,&quot;&quot;],&quot;alt&quot;:[0,&quot;&quot;]}]}],[0,{&quot;title&quot;:[0,&quot;Data Product SLAs&quot;],&quot;description&quot;:[0,&quot;Set freshness targets, track performance, and alert before deadlines miss.&quot;],&quot;image&quot;:[0,{&quot;src&quot;:[0,&quot;&quot;],&quot;alt&quot;:[0,&quot;&quot;]}]}],[0,{&quot;title&quot;:[0,&quot;Proactive Alerts&quot;],&quot;description&quot;:[0,&quot;Get notified in Slack, PagerDuty, or email the moment a Dag fails, runs long, or misses its schedule.&quot;],&quot;image&quot;:[0,{&quot;src&quot;:[0,&quot;&quot;],&quot;alt&quot;:[0,&quot;&quot;]}]}],[0,{&quot;title&quot;:[0,&quot;AI-Assisted RCA&quot;],&quot;description&quot;:[0,&quot;Get to the root cause faster with AI that pinpoints what failed and suggests fixes—without manual log analysis.&quot;],&quot;image&quot;:[0,{&quot;src&quot;:[0,&quot;&quot;],&quot;alt&quot;:[0,&quot;&quot;]}]}]]]}],[0,{&quot;id&quot;:[0,&quot;enterprise-ready&quot;],&quot;type&quot;:[0,&quot;contentBanner&quot;],&quot;noTopTitle&quot;:[0,true],&quot;title&quot;:[0,&quot;Enterprise-ready security and governance&quot;],&quot;description&quot;:[0,&quot;Built for teams with strict compliance requirements&quot;],&quot;link&quot;:[0,{&quot;text&quot;:[0,&quot;View All ➔&quot;],&quot;href&quot;:[0,&quot;/product/features#enterprise&quot;]}],&quot;content&quot;:[0,&quot;&lt;ul class=&#39;list-reset flex-container&#39;&gt;&lt;li class=&#39;flex-container&#39; style=&#39;gap:14px&#39;&gt;&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; width=&#39;15&#39; height=&#39;10&#39; viewBox=&#39;0 0 15 10&#39; fill=&#39;none&#39;&gt;&lt;path d=&#39;M14.5787 0.247623C14.8499 0.531711 14.8707 0.96339 14.6475 1.27007L14.5524 1.37869L5.75233 9.77869C5.48183 10.0369 5.07555 10.0692 4.77111 9.87551L4.64757 9.77868L0.247617 5.57868C-0.0719796 5.27361 -0.0837529 4.76721 0.22132 4.44762C0.492496 4.16353 0.922741 4.12266 1.23947 4.33135L1.35238 4.42132L5.1984 8.0928L13.4476 0.221315C13.7672 -0.0837554 14.2736 -0.0719767 14.5787 0.247623Z&#39; fill=&#39;#19BA5A&#39;/&gt;&lt;/svg&gt; SOC 2 Type II&lt;/li&gt;&lt;li class=&#39;flex-container&#39; style=&#39;gap:14px&#39;&gt;&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; width=&#39;15&#39; height=&#39;10&#39;
437 viewBox=&#39;0 0 15 10&#39; fill=&#39;none&#39;&gt;&lt;path d=&#39;M14.5787 0.247623C14.8499 0.531711 14.8707 0.96339 14.6475 1.27007L14.5524 1.37869L5.75233 9.77869C5.48183 10.0369 5.07555 10.0692 4.77111 9.87551L4.64757 9.77868L0.247617 5.57868C-0.0719796 5.27361 -0.0837529 4.76721 0.22132 4.44762C0.492496 4.16353 0.922741 4.12266 1.23947 4.33135L1.35238 4.42132L5.1984 8.0928L13.4476 0.221315C13.7672 -0.0837554 14.2736 -0.0719767 14.5787 0.247623Z&#39; fill=&#39;#19BA5A&#39;/&gt;&lt;/svg&gt; HIPAA&lt;/li&gt;&lt;li class=&#39;flex-container&#39; style=&#39;gap:14px&#39;&gt;&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; width=&#39;15&#39; height=&#39;10&#39; viewBox=&#39;0 0 15 10&#39; fill=&#39;none&#39;&gt;&lt;path d=&#39;M14.5787 0.247623C14.8499 0.531711 14.8707 0.96339 14.6475 1.27007L14.5524 1.37869L5.75233 9.77869C5.48183 10.0369 5.07555 10.0692 4.77111 9.87551L4.64757 9.77868L0.247617 5.57868C-0.0719796 5.27361 -0.0837529 4.76721 0.22132 4.44762C0.492496 4.16353 0.922741 4.12266 1.23947 4.33135L1.35238 4.42132L5.1984 8.0928L13.4476 0.221315C13.7672 -0.0837554 14.2736 -0.0719767 14.5787 0.247623Z&#39; fill=&#39;#19BA5A&#39;/&gt;&lt;/svg&gt; SSO/SCIM&lt;/li&gt;&lt;li class=&#39;flex-container&#39; style=&#39;gap:14px&#39;&gt;&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; width=&#39;15&#39; height=&#39;10&#39; viewBox=&#39;0 0 15 10&#39; fill=&#39;none&#39;&gt;&lt;path d=&#39;M14.5787 0.247623C14.8499 0.531711 14.8707 0.96339 14.6475 1.27007L14.5524 1.37869L5.75233 9.77869C5.48183 10.0369 5.07555 10.0692 4.77111 9.87551L4.64757 9.77868L0.247617 5.57868C-0.0719796 5.27361 -0.0837529 4.76721 0.22132 4.44762C0.492496 4.16353 0.922741 4.12266 1.23947 4.33135L1.35238 4.42132L5.1984 8.0928L13.4476 0.221315C13.7672 -0.0837554 14.2736 -0.0719767 14.5787 0.247623Z&#39; fill=&#39;#19BA5A&#39;/&gt;&lt;/svg&gt; RBAC&lt;/li&gt;&lt;/ul&gt;&quot;]}],[0,{&quot;id&quot;:[0,&quot;enterprise-ready&quot;],&quot;type&quot;:[0,&quot;stats&quot;],&quot;noTopTitle&quot;:[0,true],&quot;title&quot;:[0,null],&quot;description&quot;:[0,null],&quot;items&quot;:[1,[[0,{&quot;number&quot;:[0,&quot;2.5x&quot;],&quot;description&quot;:[0,&quot;Concurrent tasks vs. managed alternatives&quot;]}],[0,{&quot;number&quot;:[0,&quot;1HR&quot;],&quot;description&quot;:[0,&quot;Support response SLA&quot;]}],[0,{&quot;number&quot;:[0,&quot;Day 0&quot;],&quot;description&quot;:[0,&quot;Airflow 3 access&quot;]}]]]}],[0,{&quot;id&quot;:[0,&quot;trusted&quot;],&quot;type&quot;:[0,&quot;featureStack&quot;],&quot;noTopTitle&quot;:[0,true],&quot;title&quot;:[0,&quot;Trusted by data and AI teams.&quot;],&quot;description&quot;:[0,&quot;From ETL to LLM pipelines, teams use Astro to orchestrate critical workflows.&quot;],&quot;items&quot;:[1,[[0,{&quot;title&quot;:[0,&quot;Everlane&quot;],&quot;logo&quot;:[0,&quot;/images/logos/everlane.png&quot;],&quot;description&quot;:[0,&quot;Everlane runs 70+ critical Dags on Astro powering revenue metrics, inventory tracking, and churn prediction to support daily and strategic decisions across finance, marketing, logistics, and retail teams.&quot;],&quot;link&quot;:[0,{&quot;text&quot;:[0,&quot;Learn More ➔&quot;],&quot;href&quot;:[0,&quot;/case-studies/everlane/&quot;]}],&quot;testimonial&quot;:[0,{&quot;stat&quot;:[0,{&quot;number&quot;:[0,&quot;25%&quot;],&quot;text&quot;:[0,&quot;Cost Reduction&quot;]}],&quot;quote&quot;:[0,&quot;Astro gives us peace of mind. We don’t worry about infrastructure. We focus on delivering data.&quot;],&quot;name&quot;:[0,&quot;Madhuri Gupta&quot;],&quot;jobTitle&quot;:[0,&quot;Senior Manager of Data &amp; Analytics&quot;],&quot;company&quot;:[0,&quot;Everlane&quot;],&quot;href&quot;:[0,&quot;/case-studies/everlane/&quot;]}]}],[0,{&quot;title&quot;:[0,&quot;WeWork&quot;],&quot;description&quot;:[0,&quot;WeWork&#39;s lean data team uses Astro to orchestrate data ingestion, transformation, and reporting pipelines globally, supporting decision-making across the business.&quot;],&quot;link&quot;:[0,{&quot;text&quot;:[0,&quot;Learn More ➔&quot;],&quot;href&quot;:[0,&quot;/case-studies/wework/&quot;]}],&quot;logo&quot;:[0,&quot;/images/observe2/wework.png&quot;],&quot;testimonial&quot;:[0,{&quot;stat&quot;:[0,{&quot;number&quot;:[0,&quot;67%&quot;],&quot;text&quot;:[0,&quot;Infra Management Reduction&quot;]}],&quot;quote&quot;:[0,&quot;Astronomer makes doing more with less possible. It&#39;s a massively important part of our stack, since everything we build—models, APIs, workflows—are running on top of it.&quot;],&quot;name&quot;:[0,&quot;You Zhou&quot;],&quot;jobTitle&quot;:[0,&quot;Director of Data Engineering&quot;],&quot;company&quot;:[0,&quot;WeWork&quot;],&quot;href&quot;:[0,&quot;/case-studies/wework/&quot;]}]}],[0,{&quot;title&quot;:[0,&quot;AAA Life Insurance&quot;],&quot;logo&quot;:[0,&quot;/images/customers/new/aaa.png&quot;],&quot;description&quot;:[0,&quot;AAA Life uses Astro to run dozens of production Dags including dbt transformations, reverse ETL to CRM systems, and S3 exports to deliver timely insights to 1.6 million policyholders.&quot;],&quot;link&quot;:[0,{&quot;text&quot;:[0,&quot;Learn More ➔&quot;],&quot;href&quot;:[0,&quot;/case-studies/aaalife/&quot;]}],&quot;testimonial&quot;:[0,{&quot;stat&quot;:[0,{&quot;number&quot;:[0,&quot;80%&quot;],&quot;text&quot;:[0,&quot;Faster Trouble-shooting&quot;]}],&quot;quote&quot;:[0,&quot;The biggest impact that I&#39;
437ve seen personally is us being able to recover from failure much quicker, and that has had a significant impact on us being able to meet our SLAs.&quot;],&quot;name&quot;:[0,&quot;Josh Bickmeyer&quot;],&quot;jobTitle&quot;:[0,&quot;Manager, Analytics Engineering&quot;],&quot;company&quot;:[0,&quot;AAA LIFE INSURANCE&quot;],&quot;href&quot;:[0,&quot;/case-studies/aaalife/&quot;]}]}]]]}]]]}" ssr client="idle" opts="{&quot;name&quot;:&quot;Sections&quot;,&quot;value&quot;:true}" await-children><div class="acds-sections-wrapper"><section id="top" class="page-section page-titleBlock"><div class="page-section__content container"><div class="acds-featureSection row-flow undefined" style="anchor-name:--featureSection-top"><div class="grid-container align-stretch justify-start" style="--columns:1;--columnWidth:1fr;--gap:12px;--columnsManual:1fr"><h2 class="acds-featureSection__title acds-h2 text-center">One place to manage the complete data pipeline lifecycle.</h2><div class="acds-featureSection__description text-center acds-body-lg">Astro brings development, execution, and monitoring together so your team spends less time on infrastructure and more time shipping.</div></div><div class="acds-featureSection__children"></div></div></div></section><section id="otto-banner" class="page-section page-contentBanner"><div class="page-section__content container"><div class="acds-featureSection row-flow undefined" style="anchor-name:--featureSection-otto-banner"><div class="acds-featureSection__children"><div class="page-content-banner acds-card"><div class="grid-container align-center justify-space-between" style="--columns:1;--columnWidth:1fr;--gap:3rem;--columnsManual:390px 660px"><div class="page-content-banner__title row-flow" style="--row-flow-margin:1rem"><h2 class="acds-body-xl acds-font-family-body acds-reset-text-transform">Meet Otto, your data engineering agent</h2><p class="acds-body-md">Accelerate every part of your workflow with Otto. Author Dags, review pull requests, investigate production failures, or scope your next upgrade. Otto has the context to act, not just advise, with knowledge of your task logs, connections, and run history, plus the Airflow expertise to know what to do with it.</p><a href="/product/otto/" class="acds-body-mono acds-button block">Learn more about Otto ➔</a></div><div class="page-content-banner__content flex-container"><div class="acds-oi-prompt" aria-hidden="true"></div></div></div></div></div></div></div></section><section id="build" class="page-section page-productCard"><div class="page-section__content container"><div class="acds-featureSection row-flow undefined" style="anchor-name:--featureSection-build"><div class="acds-featureSection__children"><div class="acds-card acds-product-card acds-product-card-one-image" data-theme-color="teal"><div class="grid-container align-center justify-center" style="--columns:1;--columnWidth:1fr;--gap:30px;--columnsManual:570px 1fr"><div class="acds-product-card__text row-flow"><p class="acds-product-card__eyebrow acds-eyebrow">Build</p><h2 class="acds-h2 acds-product-card__title">Ship production-ready pipelines in minutes.</h2><p class="acds-body-mono acds-product-card__description">Astro's development toolkit covers your entire workflow with AI-assisted coding, flexible testing environments, automated CI/CD, and centralized configuration management.</p><a href="/product/features#build" class="acds-product-card__link acds-body-mono">Explore Build features ➔</a><div class="acds-product-card__items"><div class="acds-card acds-product-card__item row-flow"><h3 class="acds-product-card__item-title acds-h5 acds-text-transform-reset"><span>Astro IDE</span></h3><p class="acds-product-card__item-desecription acds-body-sm">Browser-based editor with context-aware AI that generates production-ready Airflow code. Test and validate Dags instantly, then deploy with one click. No local setup required.</p></div><div class="acds-card acds-product-card__item row-flow"><h3 class="acds-product-card__item-title acds-h5 acds-text-transform-reset"><span>Astro CLI</span></h3><p class="acds-product-card__item-desecription acds-body-sm">Run a complete local Airflow environment to build and test Dags with full control, then deploy to Astro with a single command.</p></div><div class="acds-card acds-product-card__item row-flow"><h3 class="acds-product-card__item-title acds-h5 acds-text-transform-reset"><span>Astro Terraform Provider</span></h3><p class="acds-product-card__item-desecription acds-body-sm">
437Manage Astro infrastructure as code with Terraform. Provision workspaces, deployments, and clusters using version-controlled configurations. API access also available.</p></div><div class="acds-card acds-product-card__item row-flow"><h3 class="acds-product-card__item-title acds-h5 acds-text-transform-reset"><span><span style="text-transform:lowercase !important">dbt</span> Orchestration</span></h3><p class="acds-product-card__item-desecription acds-body-sm">Native integration that turns dbt projects into Dags with model-level visibility.</p></div></div></div><div class="acds-product-card__image"><img src="/images/product/build.svg" alt="" width="100%" height="100%" loading="lazy"/></div></div></div></div></div></div></section><section id="run" class="page-section page-productCard"><div class="page-section__content container"><div class="acds-featureSection row-flow undefined" style="anchor-name:--featureSection-run"><div class="acds-featureSection__children"><div class="acds-card acds-product-card acds-product-card-one-image" data-theme-color="green"><div class="grid-container align-center justify-center" style="--columns:1;--columnWidth:1fr;--gap:30px;--columnsManual:570px 1fr"><div class="acds-product-card__text row-flow"><p class="acds-product-card__eyebrow acds-eyebrow">Run</p><h2 class="acds-h2 acds-product-card__title">Scale to any workload without managing infrastructure.</h2><p class="acds-body-mono acds-product-card__description">The Astro engine delivers 2x the performance of other Airflow solutions. Auto-scaling, high availability, and multi-cloud deployment, all made easy for you.</p><a href="/product/features#run" class="acds-product-card__link acds-body-mono">Explore Run features ➔</a><div class="acds-product-card__items"><div class="acds-card acds-product-card__item row-flow"><h3 class="acds-product-card__item-title acds-h5 acds-text-transform-reset"><span>Elastic Auto-Scaling</span></h3><p class="acds-product-card__item-desecription acds-body-sm">Workers that scale up and down based on task queue depth. Pay only for what you use.</p></div><div class="acds-card acds-product-card__item row-flow"><h3 class="acds-product-card__item-title acds-h5 acds-text-transform-reset"><span>Disaster Recovery</span></h3><p class="acds-product-card__item-desecription acds-body-sm">One-click cross-region failover with underlying data replication handled automatically.</p></div><div class="acds-card acds-product-card__item row-flow"><h3 class="acds-product-card__item-title acds-h5 acds-text-transform-reset"><span>Remote Execution</span></h3><p class="acds-product-card__item-desecription acds-body-sm">Run sensitive workloads in your own environment and dedicated hardware. All while maintaining centralized orchestration and observability in Astro.</p></div><div class="acds-card acds-product-card__item row-flow"><h3 class="acds-product-card__item-title acds-h5 acds-text-transform-reset"><span>High Availability</span></h3><p class="acds-product-card__item-desecription acds-body-sm">Multi-AZ deployments with automatic failover. 99.5% uptime SLA.</p></div></div></div><div class="acds-product-card__image"><img src="/images/product/run.svg" alt="" width="100%" height="100%" loading="lazy"/></div></div></div></div></div></div></section><section id="observe" class="page-section page-productCard"><div class="page-section__content container"><div class="acds-featureSection row-flow undefined" style="anchor-name:--featureSection-observe"><div class="acds-featureSection__children"><div class="acds-card acds-product-card acds-product-card-one-image" data-theme-color="red"><div class="grid-container align-center justify-center" style="--columns:1;--columnWidth:1fr;--gap:30px;--columnsManual:570px 1fr"><div class="acds-product-card__text row-flow"><p class="acds-product-card__eyebrow acds-eyebrow">Observe</p><h2 class="acds-h2 acds-product-card__title">Detect issues before they impact downstream systems.</h2><p class="acds-body-mono acds-product-card__description">Real-time lineage, SLA monitoring, proactive alerting, and AI-powered RCA, all built into the orchestration layer, not bolted on as a separate tool.</p><a href="/product/features#observe" class="acds-product-card__link acds-body-mono">Explore Observe features ➔</a><div class="acds-product-card__items"><div class="acds-card acds-product-card__item row-flow"><h3 class="acds-product-card__item-title acds-h5 acds-text-transform-reset"><span>Pipeline Lineage</span></h3><p class="acds-product-card__item-desecription acds-body-sm">Trace upstream/downstream dependencies across Dags, tables, and team
437s.</p></div><div class="acds-card acds-product-card__item row-flow"><h3 class="acds-product-card__item-title acds-h5 acds-text-transform-reset"><span>Data Product SLAs</span></h3><p class="acds-product-card__item-desecription acds-body-sm">Set freshness targets, track performance, and alert before deadlines miss.</p></div><div class="acds-card acds-product-card__item row-flow"><h3 class="acds-product-card__item-title acds-h5 acds-text-transform-reset"><span>Proactive Alerts</span></h3><p class="acds-product-card__item-desecription acds-body-sm">Get notified in Slack, PagerDuty, or email the moment a Dag fails, runs long, or misses its schedule.</p></div><div class="acds-card acds-product-card__item row-flow"><h3 class="acds-product-card__item-title acds-h5 acds-text-transform-reset"><span>AI-Assisted RCA</span></h3><p class="acds-product-card__item-desecription acds-body-sm">Get to the root cause faster with AI that pinpoints what failed and suggests fixes—without manual log analysis.</p></div></div></div><div class="acds-product-card__image"><img src="/images/product/observe.svg" alt="" width="100%" height="100%" loading="lazy"/></div></div></div></div></div></div></section><section id="enterprise-ready" class="page-section page-contentBanner"><div class="page-section__content container"><div class="acds-featureSection row-flow undefined" style="anchor-name:--featureSection-enterprise-ready"><div class="acds-featureSection__children"><div class="page-content-banner acds-card"><div class="grid-container align-center justify-space-between" style="--columns:1;--columnWidth:1fr;--gap:3rem;--columnsManual:390px 660px"><div class="page-content-banner__title row-flow" style="--row-flow-margin:1rem"><h2 class="acds-body-xl acds-font-family-body acds-reset-text-transform">Enterprise-ready security and governance</h2><p class="acds-body-mono">Built for teams with strict compliance requirements</p></div><div class="page-content-banner__content flex-container"><span><ul class='list-reset flex-container'><li class='flex-container' style='gap:14px'><svg xmlns='http://www.w3.org/2000/svg' width='15' height='10' viewBox='0 0 15 10' fill='none'><path d='M14.5787 0.247623C14.8499 0.531711 14.8707 0.96339 14.6475 1.27007L14.5524 1.37869L5.75233 9.77869C5.48183 10.0369 5.07555 10.0692 4.77111 9.87551L4.64757 9.77868L0.247617 5.57868C-0.0719796 5.27361 -0.0837529 4.76721 0.22132 4.44762C0.492496 4.16353 0.922741 4.12266 1.23947 4.33135L1.35238 4.42132L5.1984 8.0928L13.4476 0.221315C13.7672 -0.0837554 14.2736 -0.0719767 14.5787 0.247623Z' fill='#19BA5A'/></svg> SOC 2 Type II</li><li class='flex-container' style='gap:14px'><svg xmlns='http://www.w3.org/2000/svg' width='15' height='10' viewBox='0 0 15 10' fill='none'><path d='M14.5787 0.247623C14.8499 0.531711 14.8707 0.96339 14.6475 1.27007L14.5524 1.37869L5.75233 9.77869C5.48183 10.0369 5.07555 10.0692 4.77111 9.87551L4.64757 9.77868L0.247617 5.57868C-0.0719796 5.27361 -0.0837529 4.76721 0.22132 4.44762C0.492496 4.16353 0.922741 4.12266 1.23947 4.33135L1.35238 4.42132L5.1984 8.0928L13.4476 0.221315C13.7672 -0.0837554 14.2736 -0.0719767 14.5787 0.247623Z' fill='#19BA5A'/></svg> HIPAA</li><li class='flex-container' style='gap:14px'><svg xmlns='http://www.w3.org/2000/svg' width='15' height='10' viewBox='0 0 15 10' fill='none'><path d='M14.5787 0.247623C14.8499 0.531711 14.8707 0.96339 14.6475 1.27007L14.5524 1.37869L5.75233 9.77869C5.48183 10.0369 5.07555 10.0692 4.77111 9.87551L4.64757 9.77868L0.247617 5.57868C-0.0719796 5.27361 -0.0837529 4.76721 0.22132 4.44762C0.492496 4.16353 0.922741 4.12266 1.23947 4.33135L1.35238 4.42132L5.1984 8.0928L13.4476 0.221315C13.7672 -0.0837554 14.2736 -0.0719767 14.5787 0.247623Z' fill='#19BA5A'/></svg> SSO/SCIM</li><li class='flex-container' style='gap:14px'><svg xmlns='http://www.w3.org/2000/svg' width='15' height='10' viewBox='0 0 15 10' fill='none'><path d='M14.5787 0.247623C14.8499 0.531711 14.8707 0.96339 14.6475 1.27007L14.5524 1.37869L5.75233 9.77869C5.48183 10.0369 5.07555 10.0692 4.77111 9.87551L4.64757 9.77868L0.247617 5.57868C-0.0719796 5.27361 -0.0837529 4.76721 0.22132 4.44762C0.492496 4.16353 0.922741 4.12266 1.23947 4.33135L1.35238 4.42132L5.1984 8.0928L13.4476 0.221315C13.7672 -0.0837554 14.2736 -0.0719767 14.5787 0.247623Z' fill='#19BA5A'/></svg> RBAC</li></ul></span><a href="/product/features#enterprise" class="acds-body-mono">View All ➔</a></div></div></div></div></div></div></section><section id="enterprise-ready" class="page-section page-stats"><div class="page-section__content container"><div class="acds-featureSection row-flow undefined" style="anchor-name:--featureSection-enterprise-ready"><div class="acds-featureSection__children"><div class="acds-stats-content page-stats-content"><div class="grid-container align-stretch justify-center" style="--columns:3;--columnWidth:1fr;--gap:24px"><div class="acds-card page-stat"><span class="page-stat__number">2.5x</span><span class="page-stat__description acds-body-mono">Concurrent tasks vs. managed alternatives</span></div><div class="acds-card page-stat"><span class="page-stat__number">1HR</span><span class="page-stat__description acds-body-mono">Support response SLA</span></div><div class="acds-card page-stat"><span class="page-stat__number">Day 0</span><span class="page-stat__description acds-body-mono">Airflow 3 access</span></div></div></div></div></div></div></section><section id="trusted" class="page-section page-featureStack"><div class="page-section__content container"><div class="acds-featureSection row-flow undefined" style="anchor-name:--featureSection-trusted"><div class="acds-featureSection__children"><div class="acds-feature-stack__top text-center row-flow"><h2 class="acds-h2 acds-text-white">Trusted by data and AI teams.</h2><p class="acds-body-lg acds-text-new-moon-10">From ETL to LLM pipelines, teams use Astro to orchestrate critical workflows.</p></div><div class="acds-feature-stack__items"><div class="acds-feature-stack__item acds-card"><div class="grid-container align-center justify-space-between" style="--columns:1;--columnWidth:1fr;--gap:3rem;--columnsManual:384px 533px"><div class="acds-feature-stack__item-text row-flow"><h3 class="acds-reset-text-transform acds-text-white sr-only">Everlane</h3><img src="/images/logos/everlane.png" alt="Everlane" loading="lazy" width="150" height="auto" style="filter:brightness(0) invert(1);margin-bottom:1rem"/><p class="acds-text-new-moon-10 acds-body-mono">Everlane runs 70+ critical Dags on Astro powering revenue metrics, inventory tracking, and churn prediction to support daily and strategic decisions across finance, marketing, logistics, and retail teams.</p><a class="acds-feature-stack__item-link acds-body-mono" href="/case-studies/everlane/">Learn More ➔</a></div><div class="acds-feature-stack__item-content"><a class="acds-testimonial-card acds-card" data-theme-color="gold" href="/case-studies/everlane/"><div class="acds-testimonial-card__stat"><div class="acds-testimonial-card__stat-number acds-text-white acds-h2">25%</div><div class="acds-testimonial-card__stat-text acds-text-new-moon-10 acds-body-sm">Cost Reduction</div></div><div class="acds-testimonial-card__content row-flow"><p class="acds-testimonial-card__company acds-tag">Everlane</p><p class="acds-testimonial-card__quote acds-body-sm acds-text-new-moon-10">&quot;<!-- -->
437Astro gives us peace of mind. We don’t worry about infrastructure. We focus on delivering data.<!-- -->&quot;</p><div class="acds-testimonial-card__attribution acds-text-white flex-container"><p class="acds-testimonial-card__name acds-body-sm bold">Madhuri Gupta</p><span>·</span><p class="acds-testimonial-card__job-title acds-body-sm">Senior Manager of Data &amp; Analytics</p></div></div></a></div></div></div><div class="acds-feature-stack__item acds-card"><div class="grid-container align-center justify-space-between" style="--columns:1;--columnWidth:1fr;--gap:3rem;--columnsManual:384px 533px"><div class="acds-feature-stack__item-text row-flow"><h3 class="acds-reset-text-transform acds-text-white sr-only">WeWork</h3><img src="/images/observe2/wework.png" alt="WeWork" loading="lazy" width="150" height="auto" style="filter:brightness(0) invert(1);margin-bottom:1rem"/><p class="acds-text-new-moon-10 acds-body-mono">WeWork&#x27;s lean data team uses Astro to orchestrate data ingestion, transformation, and reporting pipelines globally, supporting decision-making across the business.</p><a class="acds-feature-stack__item-link acds-body-mono" href="/case-studies/wework/">Learn More ➔</a></div><div class="acds-feature-stack__item-content"><a class="acds-testimonial-card acds-card" data-theme-color="gold" href="/case-studies/wework/"><div class="acds-testimonial-card__stat"><div class="acds-testimonial-card__stat-number acds-text-white acds-h2">67%</div><div class="acds-testimonial-card__stat-text acds-text-new-moon-10 acds-body-sm">Infra Management Reduction</div></div><div class="acds-testimonial-card__content row-flow"><p class="acds-testimonial-card__company acds-tag">WeWork</p><p class="acds-testimonial-card__quote acds-body-sm acds-text-new-moon-10">&quot;<!-- -->Astronomer makes doing more with less possible. It&#x27;s a massively important part of our stack, since everything we build—models, APIs, workflows—are running on top of it.<!-- -->&quot;</p><div class="acds-testimonial-card__attribution acds-text-white flex-container"><p class="acds-testimonial-card__name acds-body-sm bold">You Zhou</p><span>·</span><p class="acds-testimonial-card__job-title acds-body-sm">Director of Data Engineering</p></div></div></a></div></div></div><div class="acds-feature-stack__item acds-card"><div class="grid-container align-center justify-space-between" style="--columns:1;--columnWidth:1fr;--gap:3rem;--columnsManual:384px 533px"><div class="acds-feature-stack__item-text row-flow"><h3 class="acds-reset-text-transform acds-text-white sr-only">AAA Life Insurance</h3><img src="/images/customers/new/aaa.png" alt="AAA Life Insurance" loading="lazy" width="150" height="auto" style="filter:brightness(0) invert(1);margin-bottom:1rem"/><p class="acds-text-new-moon-10 acds-body-mono">AAA Life uses Astro to run dozens of production Dags including dbt transformations, reverse ETL to CRM systems, and S3 exports to deliver timely insights to 1.6 million policyholders.</p><a class="acds-feature-stack__item-link acds-body-mono" href="/case-studies/aaalife/">Learn More ➔</a></div><div class="acds-feature-stack__item-content"><a class="acds-testimonial-card acds-card" data-theme-color="gold" href="/case-studies/aaalife/"><div class="acds-testimonial-card__stat"><div class="acds-testimonial-card__stat-number acds-text-white acds-h2">80%</div><div class="acds-testimonial-card__stat-text acds-text-new-moon-10 acds-body-sm">Faster Trouble-shooting</div></div><div class="acds-testimonial-card__content row-flow"><p class="acds-testimonial-card__company acds-tag">AAA LIFE INSURANCE</p><p class="acds-testimonial-card__quote acds-body-sm acds-text-new-moon-10">&quot;<!-- -->The biggest impact that I&#x27;ve seen personally is us being able to recover from failure much quicker, and that has had a significant impact on us being able to meet our SLAs.<!-- -->&quot;</p><div class="acds-testimonial-card__attribution acds-text-white flex-container"><p class="acds-testimonial-card__name acds-body-sm bold">Josh Bickmeyer</p><span>·</span><p class="acds-testimonial-card__job-title acds-body-sm">Manager, Analytics Engineering</p></div></div></a></div></div></div></div></div></div></div></section></div><!--astro:end--></astro-island>
437<script>(()=>{var a=(s,i,o)=>{let r=async()=>{await(await s())()},t=typeof i.value=="object"?i.value:void 0,c={rootMargin:t==null?void 0:t.rootMargin},n=new IntersectionObserver(e=>{for(let l of e)if(l.isIntersecting){n.disconnect(),r();break}},c);for(let e of o.children)n.observe(e)};(self.Astro||(self.Astro={})).visible=a;window.dispatchEvent(new Event("astro:visible"));})();</script>
437<astro-island uid="ZGTdTO" prefix="r7" component-url="/_astro/NebulaCallToAction.CQWiaKP3.js?dpl=6abd1c0e8e511d0008ca4db3" component-export="default" renderer-url="/_astro/client.CgkIogCC.js?dpl=6abd1c0e8e511d0008ca4db3" props="{}" ssr client="visible" opts="{&quot;name&quot;:&quot;NebulaCallToAction&quot;,&quot;value&quot;:true}" await-children><div class="acds-nebula-call-to-action acds-nebula-call-to-action--has-bg" aria-hidden="true"><div class="acds-nebula-call-to-action__bg"><img src="/images/footer-cta-bg.svg" alt="" width="100%" height="100%"/></div></div><!--astro:end--></astro-island>  </main> <footer class="acds-footer"><div class="acds-footer__inner"><div class="acds-footer__top"><nav class="acds-footer__nav" title="footer navigation"><div class="acds-footer__nav--list"><h3 class="acds-eyebrow" id="product">Product</h3><ul class="acds-footer__nav-list list-reset"><li><a class="acds-footer__nav-item" href="/product/">Platform Overview</a></li><li><a class="acds-footer__nav-item" href="/product/">Astro</a></li><li><a class="acds-footer__nav-item" href="/otto/">AI Features on Astro</a></li><li><a class="acds-footer__nav-item" href="/product/astro-private-cloud/">Astro Private Cloud</a></li><li><a class="acds-footer__nav-item" href="/security/">Security &amp; Trust</a></li><li><a class="acds-footer__nav-item" href="/pricing/">Pricing</a></li><li><a class="acds-footer__nav-item" href="/product-tour/">Tour</a></li></ul></div><div class="acds-footer__nav--list"><h3 class="acds-eyebrow" id="tools-services">Tools &amp; Services</h3><ul class="acds-footer__nav-list list-reset"><li><a class="acds-footer__nav-item" href="/cosmos/">Cosmos</a></li><li><a class="acds-footer__nav-item" href="https://airflow.apache.org/registry/">Registry</a></li><li><a class="acds-footer__nav-item" href="/docs/">Docs</a></li><li><a class="acds-footer__nav-item" href="/professional-services/">Professional Services</a></li><li><a class="acds-footer__nav-item" href="/product/updates/">Product Updates</a></li><li><a class="acds-footer__nav-item" href="/solutions/legacy-scheduler-migration/">Legacy Scheduler Migration</a></li><li><a class="acds-footer__nav-item" href="https://llms.astronomer.io/" aria-label="Learn More: llms.astronomer.io">Learn More</a></li></ul></div><div class="acds-footer__nav--list"><h3 class="acds-eyebrow" id="use-cases">Use Cases</h3><ul class="acds-footer__nav-list list-reset"><li><a class="acds-footer__nav-item" href="/solutions/ai-ml/">AI Ops</a></li><li><a class="acds-footer__nav-item" href="/solutions/data-observability/">Data Observability</a></li><li><a class="acds-footer__nav-item" href="/data-orchestration/">Data Orchestration</a></li><li><a class="acds-footer__nav-item" href="/solutions/etl-elt/">ETL/ELT</a></li><li><a class="acds-footer__nav-item" href="/solutions/mlops/">ML Ops</a></li><li><a class="acds-footer__nav-item" href="/solutions/analytics-and-reporting/">Operational Analytics</a></li><li><a class="acds-footer__nav-item" href="/solutions/">All Use Cases</a></li></ul></div><div class="acds-footer__nav--list"><h3 class="acds-eyebrow" id="industries">Industries</h3><ul class="acds-footer__nav-list list-reset"><li><a class="acds-footer__nav-item" href="/solutions/financial-services/">Financial Services</a></li><li><a class="acds-footer__nav-item" href="/solutions/gaming/">Gaming</a></li><li><a class="acds-footer__nav-item" href="/solutions/retail-ecommerce/">Retail</a></li><li><a class="acds-footer__nav-item" href="/solutions/manufacturing/">Manufacturing</a></li><li><a class="acds-footer__nav-item" href="/solutions/healthcare/">Healthcare</a></li><li><a class="acds-footer__nav-item" href="/solutions/">All Industries</a></li></ul></div><div class="acds-footer__nav--list"><h3 class="acds-eyebrow" id="resources">Resources</h3><ul class="acds-footer__nav-list list-reset"><li><a class="acds-footer__nav-item" href="https://academy.astronomer.io/">Academy</a></li><li><a class="acds-footer__nav-item" href="/resources/">eBooks &amp; Guides</a></li><li><a class="acds-footer__nav-item" href="/blog/">Blog</a></li><li><a class="acds-footer__nav-item" href="/events/webinars/">Webinars</a></li><li><a class="acds-footer__nav-item" href="/events/">Events</a></li><li><a class="acds-footer__nav-item" href="/podcast/">The Data Flowcast Podcast</a></li><li><a class="acds-footer__nav-item" href="/events/beyond-the-dag-data-engineering-hackathon-2026/">Beyond the Dag Hackathon</a></li><li><a class="acds-footer__nav-item" href="/resources/">All Resources</a></li></ul></div><div class="acds-footer__nav--list"><h3 class="acds-eyebrow" id="airflow">Airflow</h3><ul class="acds-footer__nav-list list-reset"><li><a class="acds-footer__nav-item" href="/airflow/">What is Airflow</a></li><li><a class="acds-footer__nav-item" href="/astro-vs-apache-airflow-oss/">Airflow on Astro</a></li><li><a class="acds-footer__nav-item" href="/airflow/3/">Airflow 3.0</a></li><li><a class="acds-footer__nav-item" href="/blog/upgrading-airflow-2-to-airflow-3-a-checklist-for-2026/">Airflow Upgrades</a></li><li>
437<a class="acds-footer__nav-item" href="/airflow/use-cases/">Airflow Use Cases</a></li><li><a class="acds-footer__nav-item" href="/airflow-2-eol/">Airflow 2.x End of Life</a></li></ul></div><div class="acds-footer__nav--list"><h3 class="acds-eyebrow" id="company">Company</h3><ul class="acds-footer__nav-list list-reset"><li><a class="acds-footer__nav-item" href="/about-us/">About Us</a></li><li><a class="acds-footer__nav-item" href="/customers/">Customers</a></li><li><a class="acds-footer__nav-item" href="/press/">Newsroom</a></li><li><a class="acds-footer__nav-item" href="/careers/">Careers</a></li><li><a class="acds-footer__nav-item" href="/contact/">Contact</a></li></ul></div><div class="acds-footer__nav--list"><h3 class="acds-eyebrow" id="support">Support</h3><ul class="acds-footer__nav-list list-reset"><li><a class="acds-footer__nav-item" href="https://support.astronomer.io/hc/en-us">Knowledge Base</a></li><li><a class="acds-footer__nav-item" href="https://status.astronomer.io/">Status</a></li><li><a class="acds-footer__nav-item" href="https://support.astronomer.io/hc/en-us">Contact Support</a></li></ul></div></nav><div class="acds-footer__social"><a href="https://github.com/astronomer" target="_blank"><img src="/icons/github copy.svg" alt="GitHub" width="22" height="22" loading="lazy"/></a><a href="https://www.youtube.com/c/astronomer" target="_blank"><img src="/icons/youtube copy.svg" alt="YouTube" width="22" height="22" loading="lazy"/></a><a href="https://www.linkedin.com/company/astronomer/" target="_blank"><img src="/icons/linkedin copy.svg" alt="LinkedIn" width="22" height="22" loading="lazy"/></a><a href="https://x.com/astronomerio" target="_blank"><img src="/icons/x.svg" alt="x" width="22" height="22" loading="lazy"/></a></div></div><div class="acds-footer__bottom"><div class="acds-footer__bottom-links"><nav title="footer small links"><ul class="acds-footer__small-links list-reset flex-container"><li><a class="acds-footer__nav-item" href="/legal/">Legal</a></li><li><a class="acds-footer__nav-item" href="/privacy/">Privacy</a></li><li><a class="acds-footer__nav-item" href="/legal/terms-of-service/">Terms of Service</a></li><li><a href="#" class="acds-footer__nav-item termly-display-preferences">Consent Preferences</a></li></ul><br/><ul class="acds-footer__small-links list-reset flex-container"><li><a href="https://app.termly.io/notify/e016d430-8e37-4d86-b2f0-f0ee9589a67a" class="acds-footer__nav-item">Do Not Sell or Share My Personal information</a></li><li><a href="https://app.termly.io/notify/e016d430-8e37-4d86-b2f0-f0ee9589a67a" class="acds-footer__nav-item">Limit the Use Of My Sensitive Personal Information</a></li></ul></nav></div><p class="acds-footer__small-text"><a class="acds-apache-link" href="https://airflow.apache.org/">Apache Airflow<sup style="font-size:0.5em">®</sup></a>, Airflow, and the Airflow logo are trademarks of the<!-- --> <a class="acds-apache-link" href="https://apache.org/">Apache Software Foundation</a>. Copyright © Astronomer <!-- -->2026<!-- -->. All rights reserved.</p></div></div></footer> <pagefind-modal reset-on-close="true"> <pagefind-modal-header> <pagefind-input placeholder="Search"></pagefind-input> <div class="acds-search-filters"> <pagefind-filter-dropdown filter="category" label="Content Type" single-select="true" hide-clear="true" sort="count-desc"></pagefind-filter-dropdown> <pagefind-filter-dropdown filter="author" label="Author" hide-clear="true" sort="count-desc"></pagefind-filter-dropdown> </div> </pagefind-modal-header> <pagefind-modal-body> <pagefind-summary></pagefind-summary> <pagefind-grouped-results></pagefind-grouped-results> </pagefind-modal-body> <pagefind-modal-footer> <pagefind-keyboard-hints></pagefind-keyboard-hints> </pagefind-modal-footer> </pagefind-modal> 
437<script type="module">
438      // pagefind-grouped-results: custom results component that organises
439      // search results into sections by content type category.
440      //
441      // Runs after pagefind-component-ui.js (both type="module", ordered by
442      // document position) so window.PagefindComponents is always available
443      // by the time connectedCallback fires.
444
445      class PagefindGroupedResults extends HTMLElement {
446        #instance = null;
447        // Maximum results to fetch across all categories
448        static #MAX_RESULTS = 500;
449        // Categories that have publication dates — sorted newest-first within each group
450        static #DATE_CATEGORIES = new Set([
451          "Blog Post",
452          "Case Study",
453          "Webinar",
454          "Podcast",
455          "eBook",
456          "Event",
457          "Press Release",
458        ]);
459        // Preferred display order for category headings
460        static #CATEGORY_ORDER = [
461          "Blog Post",
462          "Case Study",
463          "Webinar",
464          "Podcast",
465          "eBook",
466          "Event",
467          "Course",
468          "Docs",
469          "Press Release",
470          "Page",
471          "Solution",
472          "Integration",
473        ];
474
475        connectedCallback() {
476          const instanceName = this.getAttribute("instance") || "default";
477          // Wait for the Component UI bundle to register its own elements,
478          // which guarantees window.PagefindComponents is ready.
479          customElements.whenDefined("pagefind-results").then(() => {
480            this.#instance =
481              window.PagefindComponents.getInstanceManager().getInstance(
482                instanceName,
483              );
484            this.#instance.registerResults(this, { keyboardNavigation: true });
485            this.#instance.on("loading", () => this.#showLoading());
486            this.#instance.on("results", (sr) => this.#showResults(sr));
487            this.#setupKeyNav();
488          });
489        }
490
491        // Called by the instance during ARIA reconciliation.
492        reconcileAria() {}
493
494        #showLoading() {
495          this.innerHTML = `<div class="acds-grouped-results__loading" aria-live="polite">
496            <div class="pf-skeleton pf-skeleton-title"></div>
497            <div class="pf-skeleton pf-skeleton-excerpt"></div>
498            <div class="pf-skeleton pf-skeleton-title"></div>
499            <div class="pf-skeleton pf-skeleton-excerpt"></div>
500          </div>`;
501        }
502
503        async #showResults(searchResult) {
504          if (!searchResult.results?.length) {
505            // Filter-only mode: when the input is empty but filters are active,
506            // fall back to pagefind.search(null) which browses all indexed pages.
507            const filters = this.#instance.searchFilters ?? {};
508            const hasFilters = Object.values(filters).some(
509              (v) => v?.length > 0,
510            );
511            if (this.#getQuery() === "" && hasFilters) {
512              await this.#filterOnlySearch(filters);
513              return;
514            }
515            this.innerHTML = "";
516            return;
517          }
518          await this.#renderGrouped(searchResult.results);
519        }
520
521        // Read the current value of the pagefind-input element.
522        #getQuery() {
523          const inputEl = document.querySelector("pagefind-input");
524          if (!inputEl) return "";
525          // Custom element may expose .value directly; fall back to shadow DOM.
526          if (typeof inputEl.value === "string") return inputEl.value.trim();
527          const inner = inputEl.shadowRoot?.querySelector("input");
528          return (inner?.value ?? "").trim();
529        }
530
531        // Use the raw Pagefind JS API to search with no text term but active
532        // filters.  The component UI doesn't support empty-query searches, so
533        // we call pagefind.search(null, { filters }) directly.
534        async #filterOnlySearch(filters) {
535          this.#showLoading();
536          try {
537            const pf = await import("/pagefind/pagefind.js");
538            const result = await pf.search(null, { filters });
539            if (!result.results?.length) {
540              this.innerHTML = "";
541              return;
542            }
543            await this.#renderGrouped(result.results);
544          } catch {
545            this.innerHTML = "";
546          }
547        }
548
549        async #renderGrouped(results) {
550          // Fetch result data for the top N results only
551          const rawResults = results.slice(
552            0,
553            PagefindGroupedResults.#MAX_RESULTS,
554          );
555          const allData = await Promise.all(rawResults.map((r) => r.data()));
556
557          // Group by category filter value
558          const groups = new Map();
559          for (const data of allData) {
560            const category = data.filters?.category?.[0] ?? "Page";
561            if (!groups.has(category)) groups.set(category, []);
562            groups.get(category).push(data);
563          }
564
565          // Within date-based categories, sort newest first
566          for (const [category, items] of groups) {
567            if (PagefindGroupedResults.#DATE_CATEGORIES.has(category)) {
568              items.sort((a, b) => {
569                const da = a.meta?.date ?? "";
570                const db = b.meta?.date ?? "";
571                return db.localeCompare(da);
572              });
573            }
574          }
575
576          // Sort category sections by the preferred order, then alphabetically
577          const ordered = PagefindGroupedResults.#CATEGORY_ORDER.filter((c) =>
578            groups.has(c),
579          );
580          const remaining = [...groups.keys()]
581            .filter((c) => !PagefindGroupedResults.#CATEGORY_ORDER.includes(c))
582            .sort();
583
584          const html = [...ordered, ...remaining]
585            .map((category) => {
586              const groupId = `pf-group-${category
587                .toLowerCase()
588                .replace(/\s+/g, "-")
589                .replace(/[^a-z0-9-]/g, "")}`;
590              const items = groups
591                .get(category)
592                .map(
593                  (data) => `
594                <li class="acds-grouped-results__item">
595                  <a class="acds-grouped-results__link" href="${this.#safe(this.#resolveUrl(data.url))}">
596                    <span class="acds-grouped-results__title">${this.#safe(data.meta?.title ?? "Untitled")}</span>
597                    ${data.excerpt ? `<p class="acds-grouped-results__excerpt">${data.excerpt.replace("Blog|", "")}</p>` : ""}
598                  </a>
599                </li>`,
600                )
601                .join("");
602              return `
603              <section class="acds-grouped-results__section" aria-labelledby="${groupId}">
604                <h3 class="acds-grouped-results__heading" id="${groupId}">${this.#safe(category)}</h3>
605                <ul class="acds-grouped-results__list" role="list">${items}</ul>
606              </section>`;
607            })
608            .join("");
609
610          this.innerHTML = html;
611          this.#instance.reconcileAria();
612        }
613
614        // Keyboard navigation: mirror pagefind-results behaviour
615        #setupKeyNav() {
616          this.addEventListener("keydown", (e) => {
617            const focused = document.activeElement;
618            if (!focused || !this.contains(focused) || focused.tagName !== "A")
619              return;
620
621            const links = [
622              ...this.querySelectorAll(".acds-grouped-results__link"),
623            ];
624            const idx = links.indexOf(focused);
625
626            if (e.key === "ArrowDown") {
627              if (idx < links.length - 1) links[idx + 1].focus();
628              e.preventDefault();
629            } else if (e.key === "ArrowUp") {
630              if (idx > 0) {
631                links[idx - 1].focus();
632              } else {
633                this.#instance.focusPreviousInput(this);
634              }
635              e.preventDefault();
636            } else if (e.key === "Backspace") {
637              this.#instance.focusInputAndDelete(this);
638              e.preventDefault();
639            } else if (
640              e.key.length === 1 &&
641              !e.ctrlKey &&
642              !e.metaKey &&
643              !e.altKey
644            ) {
645              this.#instance.focusInputAndType(this, e.key);
646              e.preventDefault();
647            }
648          });
649        }
650
651        // Escape text for safe insertion as HTML text / attribute value.
652        // NOTE: data.excerpt is intentionally NOT passed here — it contains
653        // Pagefind-generated <mark> tags that must be preserved.
654        #safe(str) {
655          if (!str) return "";
656          return String(str)
657            .replace(/&/g, "&amp;")
658            .replace(/</g, "&lt;")
659            .replace(/>/g, "&gt;")
660            .replace(/"/g, "&quot;");
661        }
662
663        // Convert a /.docs-content/docs__astro__create-deployment.html path
664        // back to the real /docs/astro/create-deployment URL.
665        // Convert a /.academy-content/path__airflow-101.html path
666        // back to the full https://academy.astronomer.io/path/airflow-101 URL.
667        #resolveUrl(url) {
668          if (!url) return url;
669          const docsMatch = url.match(/^\/\.docs-content\/(.+)\.html$/);
670          if (docsMatch) {
671            return "/" + docsMatch[1].replace(/__/g, "/");
672          }
673          const academyMatch = url.match(/^\/\.academy-content\/(.+)\.html$/);
674          if (academyMatch) {
675            return (
676              "https://academy.astronomer.io/" +
677              academyMatch[1].replace(/__/g, "/")
678            );
679          }
680          return url;
681        }
682      }
683
684      customElements.define("pagefind-grouped-results", PagefindGroupedResults);
685
686      // =======================================================================
687      // Dropdown enhancements
688      // Runs once after pagefind-component-ui.js has registered its elements.
689      //
690      // 1. syncDropdownLabels — replaces the generic label ("Content Type") with
691      //    the active selection ("Blog Post") and marks the trigger as active.
692      // 2. setupClearButton  — injects a sticky "Clear" button at the bottom of
693      //    each dropdown menu, hidden until a value is selected.
694      // =======================================================================
695
696      customElements.whenDefined("pagefind-results").then(() => {
697        const instance =
698          window.PagefindComponents.getInstanceManager().getInstance("default");
699
700        // Re-sync labels whenever filters change
701        instance.on("filters", () => syncDropdownLabels(instance));
702
703        // Inject clear buttons into each dropdown (may be lazy-rendered)
704        document
705          .querySelectorAll("pagefind-filter-dropdown")
706          .forEach((dd) => setupClearButton(dd, instance));
707
708        // Initial pass in case filters are already set
709        syncDropdownLabels(instance);
710      });
711
712      function syncDropdownLabels(instance) {
713        const filters = instance.searchFilters ?? {};
714        document.querySelectorAll("pagefind-filter-dropdown").forEach((dd) => {
715          const key = dd.getAttribute("filter");
716          const defaultLabel = dd.getAttribute("label") || key;
717          const selected = filters[key];
718
719          // Replace label text with the active value (or restore the default)
720          const labelEl = dd.querySelector(".pf-dropdown-trigger-label");
721          if (labelEl) {
722            labelEl.textContent = selected?.length ? selected[0] : defaultLabel;
723          }
724
725          // Drive the active CSS state via a data attribute
726          if (selected?.length) {
727            dd.setAttribute("data-pf-active", "");
728          } else {
729            dd.removeAttribute("data-pf-active");
730          }
731
732          // Show/hide the inline Clear button to match filter state
733          const clearBtn = dd.querySelector(".acds-dropdown-clear-inline");
734          if (clearBtn) clearBtn.hidden = !selected?.length;
735        });
736      }
737
738      function setupClearButton(dd, instance) {
739        const key = dd.getAttribute("filter");
740
741        const inject = () => {
742          if (dd.querySelector(".acds-dropdown-clear-inline")) return;
743          const menu = dd.querySelector(".pf-dropdown-menu");
744          if (!menu) return;
745
746          const btn = document.createElement("button");
747          btn.className = "acds-dropdown-clear-inline";
748          btn.type = "button";
749          btn.textContent = "Clear";
750          btn.hidden = true; // shown via syncDropdownLabels when a value is selected
751
752          btn.addEventListener("click", (e) => {
753            e.stopPropagation();
754            instance.triggerFilter(key, []);
755            // Close the dropdown after clearing
756            requestAnimationFrame(() => {
757              const trigger = dd.querySelector(".pf-dropdown-trigger");
758              if (trigger && trigger.classList.contains("open"))
759                trigger.click();
760            });
761          });
762
763          menu.appendChild(btn);
764          obs.disconnect();
765        };
766
767        // Watch for the menu element in case it is rendered lazily
768        const obs = new MutationObserver(inject);
769        obs.observe(dd, { childList: true, subtree: true });
770        inject(); // also try immediately
771      }
772
773      // =======================================================================
774      // Search Analytics
775      // Fires to PostHog (window.posthog.capture) and GTM (window.dataLayer)
776      // for every meaningful search interaction.  Uses the same pattern as form
777      // tracking elsewhere on the site.
778      //
779      // Events fired:
780      //   Search Opened          — modal becomes visible
781      //   Search Queried         — user pauses typing (≥2 chars, debounced 600ms)
782      //   Search Filter Applied  — Content Type or Author filter changes
783      //   Search Result Clicked  — user clicks a result link
784      //   Search Closed          — modal is dismissed
785      // =======================================================================
786      customElements.whenDefined("pagefind-results").then(() => {
787        const instance =
788          window.PagefindComponents.getInstanceManager().getInstance("default");
789        const modal = document.querySelector("pagefind-modal");
790        if (!modal) return;
791
792        // ── Helper: fires to PostHog and GTM / GA4 ─────────────────────
793        function trackSearch(event, props) {
794          const payload = { component: "site_search", ...props };
795          if (window.posthog?.capture) {
796            window.posthog.capture(event, payload);
797          }
798          if (window.dataLayer) {
799            window.dataLayer.push({
800              event: "site_search",
801              search_event: event,
802              search_data: payload,
803            });
804          }
805        }
806
807        // ── Shared state ─────────────────────────────────────────────────────
808        let lastQuery = "";
809        let lastResultCount = 0;
810        let lastFilters = {};
811        let clickedResultSinceOpen = false;
812
813        // ── Modal open / close ────────────────────────────────────────────────
814        // pagefind-modal renders a native <dialog> element which carries the
815        // `open` attribute and fires the native `close` event — both are reliable
816        // regardless of how the modal is triggered (nav button, keyboard shortcut).
817        function attachModalTracking(dialog) {
818          let isOpen = dialog.hasAttribute("open");
819
820          new MutationObserver(() => {
821            const nowOpen = dialog.hasAttribute("open");
822            if (nowOpen === isOpen) return;
823            isOpen = nowOpen;
824            if (isOpen) {
825              clickedResultSinceOpen = false;
826              trackSearch("Search Opened");
827            }
828          }).observe(dialog, { attributes: true, attributeFilter: ["open"] });
829
830          dialog.addEventListener("close", () => {
831            trackSearch("Search Closed", {
832              ...(lastQuery && { query: lastQuery }),
833              result_count: lastResultCount,
834              clicked_result: clickedResultSinceOpen,
835            });
836            lastQuery = "";
837            lastResultCount = 0;
838            clickedResultSinceOpen = false;
839          });
840        }
841
842        // The <dialog> may be rendered lazily inside the custom element
843        const existingDialog =
844          modal.querySelector("dialog") ??
845          modal.shadowRoot?.querySelector("dialog");
846        if (existingDialog) {
847          attachModalTracking(existingDialog);
848        } else {
849          new MutationObserver((_, obs) => {
850            const d =
851              modal.querySelector("dialog") ??
852              modal.shadowRoot?.querySelector("dialog");
853            if (d) {
854              obs.disconnect();
855              attachModalTracking(d);
856            }
857          }).observe(modal, { childList: true, subtree: true });
858        }
859
860        // ── Search queries: debounced 600ms, min 2 chars ─────────────────────
861        let queryTimer = null;
862        modal
863          .querySelector("pagefind-input")
864          ?.addEventListener("input", (e) => {
865            // input bubbles from the shadow-DOM <input> — composedPath gives us
866            // the actual element so we can read its current value.
867            const query = (e.composedPath?.()?.[0]?.value ?? "").trim();
868            lastQuery = query;
869            clearTimeout(queryTimer);
870            if (query.length < 2) return;
871            queryTimer = setTimeout(() => {
872              trackSearch("Search Queried", {
873                query,
874                result_count: lastResultCount,
875                ...(Object.keys(instance.searchFilters ?? {}).length && {
876                  filters: instance.searchFilters,
877                }),
878              });
879            }, 600);
880          });
881
882        // Keep lastResultCount current for Search Closed
883        instance.on("results", (sr) => {
884          lastResultCount = sr.results?.length ?? 0;
885        });
886
887        // ── Filter applied ────────────────────────────────────────────────────
888        instance.on("filters", () => {
889          const newFilters = instance.searchFilters ?? {};
890          const allKeys = new Set([
891            ...Object.keys(lastFilters),
892            ...Object.keys(newFilters),
893          ]);
894          for (const key of allKeys) {
895            const prev = (lastFilters[key] ?? []).join(",");
896            const curr = (newFilters[key] ?? []).join(",");
897            if (prev !== curr && curr) {
898              trackSearch("Search Filter Applied", {
899                filter_type: key,
900                filter_value: newFilters[key]?.[0],
901                ...(lastQuery && { query: lastQuery }),
902              });
903            }
904          }
905          lastFilters = { ...newFilters };
906        });
907
908        // ── Result clicks ─────────────────────────────────────────────────────
909        // Delegated listener on the modal so it works even after re-renders
910        modal.addEventListener("click", (e) => {
911          const link = e.target.closest?.(".acds-grouped-results__link");
912          if (!link) return;
913
914          const section = link.closest(".acds-grouped-results__section");
915          const category =
916            section
917              ?.querySelector(".acds-grouped-results__heading")
918              ?.textContent?.trim() ?? "";
919          const title =
920            link
921              .querySelector(".acds-grouped-results__title")
922              ?.textContent?.trim() ?? "";
923          const href = link.getAttribute("href") ?? "";
924          const allLinks = [
925            ...modal.querySelectorAll(".acds-grouped-results__link"),
926          ];
927          const position = allLinks.indexOf(link) + 1;
928
929          clickedResultSinceOpen = true;
930          trackSearch("Search Result Clicked", {
931            query: lastQuery || undefined,
932            result_url: href,
933            result_title: title,
934            result_category: category,
935            result_position: position,
936            ...(Object.keys(instance.searchFilters ?? {}).length && {
937              filters: instance.searchFilters,
938            }),
939          });
940        });
941      });
942    </script>
942<script>
943      window.addEventListener("DOMContentLoaded", () => {
944        if (
945          !document.querySelector(".headerNav") &&
946          document.querySelector(".menuToggle")
947        ) {
948          document.querySelector(".menuToggle").remove();
949        }
950        setTimeout(() => {
951          document.querySelector("body").classList.remove("preload");
952        }, 100);
953
954        if (window.location.search.includes("utm")) {
955          const params = new URLSearchParams(window.location.search);
956          [...document.querySelectorAll("a[href]")].forEach((e) => {
957            const url = new URL(e.href);
958            for (let [k, v] of params.entries()) {
959              url.searchParams.set(k, v);
960            }
961            e.href = url.toString();
962          });
963        }
964      });
965    </script>
965</body> </html>  
965<script>
966  // Make sure Wistia's marketo object is always deleted so the webianr recap form always shows
967  document.addEventListener("DOMContentLoaded", function () {
968    localStorage.removeItem("wistia");
969  });
970
971  // Globally Available IntersectionObserve to lazy load videos with class .lazy
972  // https://web.dev/articles/lazy-loading-video
973  document.addEventListener("DOMContentLoaded", function () {
974    let lazyVideos = [].slice.call(document.querySelectorAll("video.lazy"));
975
976    if ("IntersectionObserver" in window) {
977      let lazyVideoObserver = new IntersectionObserver(function (
978        entries,
979        observer,
980      ) {
981        entries.forEach(function (video) {
982          if (video.isIntersecting) {
983            for (let source in video.target.children) {
984              let videoSource = video.target.children[source];
985              if (
986                typeof videoSource.tagName === "string" &&
987                videoSource.tagName === "SOURCE"
988              ) {
989                videoSource.src = videoSource.dataset.src;
990              }
991            }
992
993            video.target.load();
994            video.target.classList.remove("lazy");
995            lazyVideoObserver.unobserve(video.target);
996          }
997        });
998      });
999
1000      lazyVideos.forEach(function (lazyVideo) {
1001        lazyVideoObserver.observe(lazyVideo);
1002      });
1003    }
1004  });
1005</script>
1005 
1005<script>
1006  document.addEventListener("DOMContentLoaded", function () {
1007    const modelContext =
1008      document.modelContext ||
1009      (typeof navigator !== "undefined" ? navigator.modelContext : undefined);
1010
1011    if (!modelContext) {
1012      return;
1013    }
1014
1015    function toSameOriginUrl(inputPath, fallbackPath) {
1016      const rawPath =
1017        typeof inputPath === "string" && inputPath.trim()
1018          ? inputPath.trim()
1019          : fallbackPath;
1020      const pathWithLeadingSlash = rawPath.startsWith("/")
1021        ? rawPath
1022        : `/${rawPath}`;
1023      const normalized = new URL(pathWithLeadingSlash, window.location.origin);
1024
1025      if (normalized.origin !== window.location.origin) {
1026        throw new Error("Cross-origin navigation is not allowed");
1027      }
1028
1029      return normalized;
1030    }
1031
1032    const tools = [
1033      {
1034        name: "open_docs",
1035        description: "Navigate to Astronomer documentation.",
1036        inputSchema: {
1037          type: "object",
1038          properties: {
1039            path: {
1040              type: "string",
1041              description: "Optional docs path, for example /docs/astro/.",
1042            },
1043          },
1044        },
1045        execute: async function (input) {
1046          try {
1047            const requestedPath =
1048              input && typeof input.path === "string" ? input.path.trim() : "";
1049            const docsPath = requestedPath
1050              ? requestedPath.startsWith("/docs")
1051                ? requestedPath
1052                : `/docs/${requestedPath.replace(/^\/+/, "")}`
1053              : "/docs";
1054            const url = toSameOriginUrl(docsPath, "/docs");
1055            const href = `${url.pathname}${url.search}${url.hash}`;
1056            window.location.assign(href);
1057
1058            return {
1059              ok: true,
1060              url: url.toString(),
1061            };
1062          } catch {
1063            return {
1064              ok: false,
1065              error: "Invalid path",
1066            };
1067          }
1068        },
1069      },
1070      {
1071        name: "book_demo",
1072        description: "Navigate to the Astronomer demo booking page.",
1073        inputSchema: {
1074          type: "object",
1075          properties: {},
1076        },
1077        execute: async function () {
1078          const href = "/book-a-demo";
1079          window.location.assign(href);
1080
1081          return {
1082            ok: true,
1083            url: new URL(href, window.location.origin).toString(),
1084          };
1085        },
1086      },
1087      {
1088        name: "open_site_path",
1089        description:
1090          "Navigate to a path on www.astronomer.io while staying on the same origin.",
1091        inputSchema: {
1092          type: "object",
1093          properties: {
1094            path: {
1095              type: "string",
1096              description: "Absolute path on the site, for example /contact.",
1097            },
1098          },
1099          required: ["path"],
1100        },
1101        execute: async function (input) {
1102          try {
1103            const rawPath =
1104              input && typeof input.path === "string" ? input.path.trim() : "";
1105            const url = toSameOriginUrl(rawPath, "/");
1106            const href = `${url.pathname}${url.search}${url.hash}`;
1107            window.location.assign(href);
1108
1109            return {
1110              ok: true,
1111              url: url.toString(),
1112            };
1113          } catch {
1114            return {
1115              ok: false,
1116              error: "Invalid path",
1117            };
1118          }
1119        },
1120      },
1121      {
1122        name: "get_discovery_endpoints",
1123        description:
1124          "Return machine-readable discovery endpoints published by www.astronomer.io.",
1125        inputSchema: {
1126          type: "object",
1127          properties: {},
1128        },
1129        annotations: {
1130          readOnlyHint: true,
1131        },
1132        execute: async function () {
1133          const origin = window.location.origin;
1134          return {
1135            apiCatalog: `${origin}/.well-known/api-catalog`,
1136            openApi: `${origin}/.well-known/openapi.json`,
1137            agentSkills: `${origin}/.well-known/agent-skills/index.json`,
1138            mcpServerCard: `${origin}/.well-known/mcp/server-card.json`,
1139          };
1140        },
1141      },
1142    ];
1143
1144    if (typeof modelContext.registerTool === "function") {
1145      const abortController = new AbortController();
1146
1147      Promise.allSettled(
1148        tools.map((tool) =>
1149          modelContext.registerTool(tool, {
1150            signal: abortController.signal,
1151          }),
1152        ),
1153      ).catch(function () {
1154        // Ignore registration failures on browsers that expose partial previews.
1155      });
1156
1157      window.addEventListener(
1158        "pagehide",
1159        function () {
1160          abortController.abort("navigation");
1161        },
1162        { once: true },
1163      );
1164    }
1165
1166    const navigatorModelContext =
1167      typeof navigator !== "undefined" ? navigator.modelContext : undefined;
1168
1169    if (
1170      navigatorModelContext &&
1171      typeof navigatorModelContext.provideContext === "function"
1172    ) {
1173      try {
1174        navigatorModelContext.provideContext({
1175          tools: tools.map((tool) => ({
1176            name: tool.name,
1177            description: tool.description,
1178            inputSchema: tool.inputSchema,
1179          })),
1180        });
1181      } catch {
1182        // Ignore provideContext errors for experimental implementations.
1183      }
1184    }
1185  });
1186</script>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.