1<!DOCTYPE html><html lang="en" dir="ltr" data-theme="dark" data-has-toc data-has-sidebar class="astro-lkmsl3sa"> <head><meta charset="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><title>How pgflow Works | pgflow (Workflow Engine for Supabase)</title><link rel="canonical" href="https://www.pgflow.dev/concepts/how-pgflow-works/"/><link rel="sitemap" href="/sitemap-index.xml"/>
1<script defer data-domain="www.pgflow.dev" data-api="https://wispy-pond-c6f8.jumski.workers.dev/data/event" src="https://wispy-pond-c6f8.jumski.workers.dev/assets/script.hash.outbound-links.pageview-props.tagged-events.js"></script>
1<script>window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }</script>
1<link href="https://www.pgflow.dev/news/rss.xml" rel="alternate" title="News" type="application/rss+xml"/><link rel="shortcut icon" href="/favicons/favicon.ico" type="image/x-icon"/><meta name="generator" content="Astro v5.15.9"/><meta name="generator" content="Starlight v0.34.8"/><meta property="og:title" content="How pgflow Works"/><meta property="og:url" content="https://www.pgflow.dev/concepts/how-pgflow-works/"/><meta property="og:locale" content="en"/><meta property="og:description" content="A gentle introduction to pgflow's execution model, state machine, and workflow lifecycle"/><meta property="og:site_name" content="pgflow (Workflow Engine for Supabase)"/><meta name="twitter:card" content="summary_large_image"/><meta name="description" content="A gentle introduction to pgflow's execution model, state machine, and workflow lifecycle"/><meta name="twitter:site" content="@pgflow_dev"/><meta name="robots" content="noindex,nofollow"/><meta property="og:image" content="https://www.pgflow.dev/og-image.jpg"/><meta property="twitter:image" content="https://www.pgflow.dev/og-image.jpg"/><meta property="og:type" content="website"/>
1<script> 2 window.StarlightThemeProvider = (() => { 3 const storedTheme = 4 typeof localStorage !== 'undefined' && localStorage.getItem('starlight-theme'); 5 const theme = 6 storedTheme || 7 (window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark'); 8 document.documentElement.dataset.theme = theme === 'light' ? 'light' : 'dark'; 9 return { 10 updatePickers(theme = storedTheme || 'auto') { 11 document.querySelectorAll('starlight-theme-select').forEach((picker) => { 12 const select = picker.querySelector('select'); 13 if (select) select.value = theme; 14 /** @type {HTMLTemplateElement | null} */ 15 const tmpl = document.querySelector(`#theme-icons`); 16 const newIcon = tmpl && tmpl.content.querySelector('.' + theme); 17 if (newIcon) { 18 const oldIcon = picker.querySelector('svg.label-icon'); 19 if (oldIcon) { 20 oldIcon.replaceChildren(...newIcon.cloneNode(true).childNodes); 21 } 22 } 23 }); 24 }, 25 }; 26 })(); 27</script>
27<template id="theme-icons"><svg aria-hidden="true" class="light astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M5 12a1 1 0 0 0-1-1H3a1 1 0 0 0 0 2h1a1 1 0 0 0 1-1Zm.64 5-.71.71a1 1 0 0 0 0 1.41 1 1 0 0 0 1.41 0l.71-.71A1 1 0 0 0 5.64 17ZM12 5a1 1 0 0 0 1-1V3a1 1 0 0 0-2 0v1a1 1 0 0 0 1 1Zm5.66 2.34a1 1 0 0 0 .7-.29l.71-.71a1 1 0 1 0-1.41-1.41l-.66.71a1 1 0 0 0 0 1.41 1 1 0 0 0 .66.29Zm-12-.29a1 1 0 0 0 1.41 0 1 1 0 0 0 0-1.41l-.71-.71a1.004 1.004 0 1 0-1.43 1.41l.73.71ZM21 11h-1a1 1 0 0 0 0 2h1a1 1 0 0 0 0-2Zm-2.64 6A1 1 0 0 0 17 18.36l.71.71a1 1 0 0 0 1.41 0 1 1 0 0 0 0-1.41l-.76-.66ZM12 6.5a5.5 5.5 0 1 0 5.5 5.5A5.51 5.51 0 0 0 12 6.5Zm0 9a3.5 3.5 0 1 1 0-7 3.5 3.5 0 0 1 0 7Zm0 3.5a1 1 0 0 0-1 1v1a1 1 0 0 0 2 0v-1a1 1 0 0 0-1-1Z"/></svg><svg aria-hidden="true" class="dark astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M21.64 13a1 1 0 0 0-1.05-.14 8.049 8.049 0 0 1-3.37.73 8.15 8.15 0 0 1-8.14-8.1 8.59 8.59 0 0 1 .25-2A1 1 0 0 0 8 2.36a10.14 10.14 0 1 0 14 11.69 1 1 0 0 0-.36-1.05Zm-9.5 6.69A8.14 8.14 0 0 1 7.08 5.22v.27a10.15 10.15 0 0 0 10.14 10.14 9.784 9.784 0 0 0 2.1-.22 8.11 8.11 0 0 1-7.18 4.32v-.04Z"/></svg><svg aria-hidden="true" class="auto astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M21 14h-1V7a3 3 0 0 0-3-3H7a3 3 0 0 0-3 3v7H3a1 1 0 0 0-1 1v2a3 3 0 0 0 3 3h14a3 3 0 0 0 3-3v-2a1 1 0 0 0-1-1ZM6 7a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v7H6V7Zm14 10a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-1h16v1Z"/></svg></template><link rel="stylesheet" href="/_astro/print.DNXP8c50.css" media="print"><link rel="stylesheet" href="/_astro/Authors.DOjgMhCN.css"> 28<style>.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.hero-anim{width:100%;margin:0;padding:0}.animation-wrapper{position:relative;width:100%}.anim-ctrl{position:absolute;bottom:12px;right:12px;z-index:10;background:transparent;border:1px solid var(--sl-color-accent);color:var(--sl-color-accent-high);padding:4px 10px;border-radius:3px;cursor:pointer;font-size:11px;font-weight:500;line-height:1.4;transition:all .2s;opacity:.7}.anim-ctrl:hover{opacity:1;background-color:var(--sl-color-accent-low)}.anim-ctrl:focus-visible{outline:2px solid var(--sl-color-accent);outline-offset:2px}.anim-ctrl:active{background-color:var(--sl-color-accent);color:var(--sl-color-white)}#animation-container{width:100%;margin:0;padding:0;background:transparent;position:relative;overflow:visible}.hero-anim-caption{font-size:14px;color:#a0b5b0;margin:12px 0 0;text-align:center}.hero-anim-caption strong{color:#e0e8e5}.anim-learn{font-weight:600;color:#5b8def;text-decoration:none;margin-left:8px}.anim-learn:hover{text-decoration:underline}#dag-animation{width:100%;height:auto;display:block}.node rect{transition:fill .3s ease,stroke .3s ease,box-shadow .3s ease;stroke-width:2.5}.node text{fill:#fff;font-size:16px;font-weight:600;text-anchor:middle;dominant-baseline:middle;pointer-events:none}.hero-anim[data-large=true] .node text{font-size:20px}.node rect{stroke-width:2.5;filter:drop-shadow(3px 4px 4px rgba(0,0,0,.25))}.node.pending rect{fill:#3d524d;stroke:#607b75}.node.running rect{fill:#3b5bdb;stroke:#5b8def}.node.failed rect{fill:#c94a2e;stroke:#f08060}.node.retrying rect{fill:#4460ff;stroke:#7a91ff;stroke-dasharray:8 4;animation:dashflow 1.2s linear infinite}.node.success rect{fill:#177a51;stroke:#20a56f}@keyframes dashflow{to{stroke-dashoffset:-12}}@media(prefers-reduced-motion:reduce){.node.retrying rect{animation:none}.node.running rect,.node.retrying rect{filter:none}.hero-anim[data-anim-state=running]{animation-play-state:paused}}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.edge{stroke:#607b75;stroke-width:2.5;fill:none;opacity:.6;stroke-dasharray:8 4}.edge.active{stroke:#6b8c85;stroke-width:3;opacity:.9;stroke-dasharray:8 4;animation:dash-flow 1s linear infinite}.edge.active.complete{stroke:#1a9c64;stroke-dasharray:none;animation:none}@keyframes dash-flow{to{stroke-dashoffset:-12}} 29@layer starlight.components{:root{--sl-badge-default-border: var(--sl-color-accent);--sl-badge-default-bg: var(--sl-color-accent-low);--sl-badge-default-text: #fff;--sl-badge-note-border: var(--sl-color-blue);--sl-badge-note-bg: var(--sl-color-blue-low);--sl-badge-note-text: #fff;--sl-badge-danger-border: var(--sl-color-red);--sl-badge-danger-bg: var(--sl-color-red-low);--sl-badge-danger-text: #fff;--sl-badge-success-border: var(--sl-color-green);--sl-badge-success-bg: var(--sl-color-green-low);--sl-badge-success-text: #fff;--sl-badge-caution-border: var(--sl-color-orange);--sl-badge-caution-bg: var(--sl-color-orange-low);--sl-badge-caution-text: #fff;--sl-badge-tip-border: var(--sl-color-purple);--sl-badge-tip-bg: var(--sl-color-purple-low);--sl-badge-tip-text: #fff}[data-theme=light]:root{--sl-badge-default-bg: var(--sl-color-accent-high);--sl-badge-note-bg: var(--sl-color-blue-high);--sl-badge-danger-bg: var(--sl-color-red-high);--sl-badge-success-bg: var(--sl-color-green-high);--sl-badge-caution-bg: var(--sl-color-orange-high);--sl-badge-tip-bg: var(--sl-color-purple-high)}.sl-badge:where(.astro-auj3iet6){display:inline-block;border:1px solid var(--sl-color-border-badge);border-radius:.25rem;font-family:var(--sl-font-system-mono);line-height:normal;color:var(--sl-color-text-badge);background-color:var(--sl-color-bg-badge);overflow-wrap:anywhere}.sidebar-content .sl-badge:where(.astro-auj3iet6){line-height:1;font-size:var(--sl-text-xs);padding:.125rem .375rem}.sidebar-content a[aria-current=page]>.sl-badge:where(.astro-auj3iet6){--sl-color-bg-badge: transparent;--sl-color-border-badge: currentColor;color:inherit}.default:where(.astro-auj3iet6){--sl-color-bg-badge: var(--sl-badge-default-bg);--sl-color-border-badge: var(--sl-badge-default-border);--sl-color-text-badge: var(--sl-badge-default-text)}.note:where(.astro-auj3iet6){--sl-color-bg-badge: var(--sl-badge-note-bg);--sl-color-border-badge: var(--sl-badge-note-border);--sl-color-text-badge: var(--sl-badge-note-text)}.danger:where(.astro-auj3iet6){--sl-color-bg-badge: var(--sl-badge-danger-bg);--sl-color-border-badge: var(--sl-badge-danger-border);--sl-color-text-badge: var(--sl-badge-danger-text)}
29.success:where(.astro-auj3iet6){--sl-color-bg-badge: var(--sl-badge-success-bg);--sl-color-border-badge: var(--sl-badge-success-border);--sl-color-text-badge: var(--sl-badge-success-text)}.tip:where(.astro-auj3iet6){--sl-color-bg-badge: var(--sl-badge-tip-bg);--sl-color-border-badge: var(--sl-badge-tip-border);--sl-color-text-badge: var(--sl-badge-tip-text)}.caution:where(.astro-auj3iet6){--sl-color-bg-badge: var(--sl-badge-caution-bg);--sl-color-border-badge: var(--sl-badge-caution-border);--sl-color-text-badge: var(--sl-badge-caution-text)}.small:where(.astro-auj3iet6){font-size:var(--sl-text-xs);padding:.125rem .25rem}.medium:where(.astro-auj3iet6){font-size:var(--sl-text-sm);padding:.175rem .35rem}.large:where(.astro-auj3iet6){font-size:var(--sl-text-base);padding:.225rem .45rem}.sl-markdown-content :is(h1,h2,h3,h4,h5,h6) .sl-badge:where(.astro-auj3iet6){vertical-align:middle}} 30@layer starlight.components{.card-grid:where(.astro-y4xfamor){display:grid;grid-template-columns:100%;gap:1rem}.card-grid:where(.astro-y4xfamor)>*{margin-top:0!important}@media(min-width:50rem){.card-grid:where(.astro-y4xfamor){grid-template-columns:1fr 1fr;gap:1.5rem}.stagger:where(.astro-y4xfamor){--stagger-height: 5rem;padding-bottom:var(--stagger-height)}.stagger:where(.astro-y4xfamor)>*:nth-child(2n){transform:translateY(var(--stagger-height))}}} 31@layer starlight.components{.card:where(.astro-5y3mj7uu){--sl-card-border: var(--sl-color-purple);--sl-card-bg: var(--sl-color-purple-low);border:1px solid var(--sl-color-gray-5);background-color:var(--sl-color-black);padding:clamp(1rem,calc(.125rem + 3vw),2.5rem);flex-direction:column;gap:clamp(.5rem,calc(.125rem + 1vw),1rem)}.card:where(.astro-5y3mj7uu):nth-child(4n+1){--sl-card-border: var(--sl-color-orange);--sl-card-bg: var(--sl-color-orange-low)}.card:where(.astro-5y3mj7uu):nth-child(4n+3){--sl-card-border: var(--sl-color-green);--sl-card-bg: var(--sl-color-green-low)}.card:where(.astro-5y3mj7uu):nth-child(4n+4){--sl-card-border: var(--sl-color-red);--sl-card-bg: var(--sl-color-red-low)}.card:where(.astro-5y3mj7uu):nth-child(4n+5){--sl-card-border: var(--sl-color-blue);--sl-card-bg: var(--sl-color-blue-low)}.title:where(.astro-5y3mj7uu){font-weight:600;font-size:var(--sl-text-h4);color:var(--sl-color-white);line-height:var(--sl-line-height-headings);gap:1rem;align-items:center}.card:where(.astro-5y3mj7uu) .icon:where(.astro-5y3mj7uu){border:1px solid var(--sl-card-border);background-color:var(--sl-card-bg);padding:.2em;border-radius:.25rem;flex-shrink:0}.card:where(.astro-5y3mj7uu) .body:where(.astro-5y3mj7uu){margin:0;font-size:clamp(var(--sl-text-sm),calc(.5rem + 1vw),var(--sl-text-body))}} 32@layer starlight.components{svg:where(.astro-i27iqf3l){color:var(--sl-icon-color);font-size:var(--sl-icon-size, 1em);width:1em;height:1em}} 33@layer starlight.components{starlight-tabs:where(.astro-iavvnwyp){display:block}.tablist-wrapper:where(.astro-iavvnwyp){overflow-x:auto}:where(.astro-iavvnwyp)[role=tablist]{display:flex;list-style:none;border-bottom:2px solid var(--sl-color-gray-5);padding:0}.tab:where(.astro-iavvnwyp){margin-bottom:-2px}.tab:where(.astro-iavvnwyp)>:where(.astro-iavvnwyp)[role=tab]{display:flex;align-items:center;gap:.5rem;padding:0 1.25rem;text-decoration:none;border-bottom:2px solid var(--sl-color-gray-5);color:var(--sl-color-gray-3);outline-offset:var(--sl-outline-offset-inside);overflow-wrap:initial}.tab:where(.astro-iavvnwyp) :where(.astro-iavvnwyp)[role=tab][aria-selected=true]{color:var(--sl-color-white);border-color:var(--sl-color-text-accent);font-weight:600}.tablist-wrapper:where(.astro-iavvnwyp)~[role=tabpanel]{margin-top:1rem}} 34@layer starlight.components{.sl-link-card:where(.astro-bhcct7ef){display:grid;grid-template-columns:1fr auto;gap:.5rem;border:1px solid var(--sl-color-gray-5);border-radius:.5rem;padding:1rem;box-shadow:var(--sl-shadow-sm);position:relative}a:where(.astro-bhcct7ef){text-decoration:none;line-height:var(--sl-line-height-headings)}a:where(.astro-bhcct7ef):before{content:"";position:absolute;inset:0}.stack:where(.astro-bhcct7ef){flex-direction:column;gap:.5rem}.title:where(.astro-bhcct7ef){color:var(--sl-color-white);font-weight:600;font-size:var(--sl-text-lg)}.description:where(.astro-bhcct7ef){color:var(--sl-color-gray-3);line-height:1.5}.icon:where(.astro-bhcct7ef){color:var(--sl-color-gray-3)}.sl-link-card:where(.astro-bhcct7ef):hover{background:var(--sl-color-gray-7, var(--sl-color-gray-6));border-color:var(--sl-color-gray-2)}.sl-link-card:where(.astro-bhcct7ef):hover .icon:where(.astro-bhcct7ef){color:var(--sl-color-white)}} 35@layer starlight.components{.sl-steps{--bullet-size: calc(var(--sl-line-height) * 1rem);--bullet-margin: .375rem;list-style:none;counter-reset:steps-counter var(--sl-steps-start, 0);padding-inline-start:0}.sl-steps>li{counter-increment:steps-counter;position:relative;padding-inline-start:calc(var(--bullet-size) + 1rem);padding-bottom:1px;min-height:calc(var(--bullet-size) + var(--bullet-margin))}.sl-steps>li+li{margin-top:0}.sl-steps>li:before{content:counter(steps-counter);position:absolute;top:0;inset-inline-start:0;width:var(--bullet-size);height:var(--bullet-size);line-height:var(--bullet-size);font-size:var(--sl-text-xs);font-weight:600;text-align:center;color:var(--sl-color-white);background-color:var(--sl-color-gray-6);border-radius:99rem;box-shadow:inset 0 0 0 1px var(--sl-color-gray-5)}.sl-steps>li:after{--guide-width: 1px;content:"";position:absolute;top:calc(var(--bullet-size) + var(--bullet-margin));bottom:var(--bullet-margin);inset-inline-start:calc((var(--bullet-size) - var(--guide-width)) / 2);width:var(--guide-width);background-color:var(--sl-color-hairline-light)}}@layer starlight.content{.sl-steps>li>:first-child{--lh: calc(1em * var(--sl-line-height));--shift-y: calc(.5 * (var(--bullet-size) - var(--lh)));
35transform:translateY(var(--shift-y));margin-bottom:var(--shift-y)}.sl-steps>li>:first-child:where(h1,h2,h3,h4,h5,h6){--lh: calc(1em * var(--sl-line-height-headings))}@supports (--prop: 1lh){.sl-steps>li>:first-child{--lh: 1lh}}} 36@layer starlight.components{starlight-file-tree:where(.astro-i6hikuar){--x-space: 1.5rem;--y-space: .125rem;--y-pad: 0;display:block;border:1px solid var(--sl-color-gray-5);padding:1rem;background-color:var(--sl-color-gray-6);font-size:var(--sl-text-xs);font-family:var(--__sl-font-mono);overflow-x:auto}starlight-file-tree:where(.astro-i6hikuar) .directory>details{border:0;padding:0;padding-inline-start:var(--x-space);background:transparent}starlight-file-tree:where(.astro-i6hikuar) .directory>details>summary{margin-inline-start:calc(-1 * var(--x-space));border:0;padding:var(--y-pad) .625rem;font-weight:400;color:var(--sl-color-white);max-width:100%}starlight-file-tree:where(.astro-i6hikuar) .directory>details>summary::marker,starlight-file-tree:where(.astro-i6hikuar) .directory>details>summary::-webkit-details-marker{color:var(--sl-color-gray-3)}starlight-file-tree:where(.astro-i6hikuar) .directory>details>summary:hover,starlight-file-tree:where(.astro-i6hikuar) .directory>details>summary:hover .tree-icon{cursor:pointer;color:var(--sl-color-text-accent);fill:currentColor}starlight-file-tree:where(.astro-i6hikuar) .directory>details>summary:hover~ul{border-color:var(--sl-color-gray-4)}starlight-file-tree:where(.astro-i6hikuar) .directory>details>summary:hover .highlight .tree-icon{color:var(--sl-color-text-invert);fill:currentColor}starlight-file-tree:where(.astro-i6hikuar) ul{margin-inline-start:.5rem;border-inline-start:1px solid var(--sl-color-gray-5);padding:0;padding-inline-start:.125rem;list-style:none}starlight-file-tree:where(.astro-i6hikuar)>ul{margin:0;border:0;padding:0}starlight-file-tree:where(.astro-i6hikuar) li{margin:var(--y-space) 0;padding:var(--y-pad) 0}starlight-file-tree:where(.astro-i6hikuar) .file{margin-inline-start:calc(var(--x-space) - .125rem);color:var(--sl-color-white)}starlight-file-tree:where(.astro-i6hikuar) .tree-entry{display:inline-flex;align-items:flex-start;flex-wrap:wrap;max-width:calc(100% - 1rem)}@media(min-width:30em){starlight-file-tree:where(.astro-i6hikuar) .tree-entry{flex-wrap:nowrap}}starlight-file-tree:where(.astro-i6hikuar) .tree-entry>:first-child{flex-shrink:0}starlight-file-tree:where(.astro-i6hikuar) .empty{color:var(--sl-color-gray-3);padding-inline-start:.375rem}starlight-file-tree:where(.astro-i6hikuar) .comment{color:var(--sl-color-gray-3);padding-inline-start:1.625rem;max-width:24rem;min-width:12rem}starlight-file-tree:where(.astro-i6hikuar) .highlight{display:inline-block;border-radius:.25rem;padding-inline-end:.5rem;color:var(--sl-color-text-invert);background-color:var(--sl-color-text-accent)}starlight-file-tree:where(.astro-i6hikuar) svg{display:inline;fill:var(--sl-color-gray-3);vertical-align:middle;margin-inline:.25rem .375rem;width:.875rem;height:.875rem}starlight-file-tree:where(.astro-i6hikuar) .highlight svg.tree-icon{fill:currentColor}} 37@layer starlight.components{.sl-link-button:where(.astro-5v627irg){align-items:center;border:1px solid transparent;border-radius:999rem;display:inline-flex;font-size:var(--sl-text-sm);gap:.5em;line-height:1.1875;outline-offset:.25rem;padding:.4375rem 1.125rem;text-decoration:none}.sl-link-button:where(.astro-5v627irg).primary{background:var(--sl-color-text-accent);border-color:var(--sl-color-text-accent);color:var(--sl-color-black)}.sl-link-button:where(.astro-5v627irg).primary:hover{color:var(--sl-color-black)}.sl-link-button:where(.astro-5v627irg).secondary{border-color:inherit;color:var(--sl-color-white)}.sl-link-button:where(.astro-5v627irg).minimal{color:var(--sl-color-white);padding-inline:0}.sl-link-button:where(.astro-5v627irg) svg{flex-shrink:0}@media(min-width:50rem){.sl-link-button:where(.astro-5v627irg){font-size:var(--sl-text-base);padding:.9375rem 1.25rem}}.sl-markdown-content .sl-link-button:where(.astro-5v627irg){margin-inline-end:1rem}.sl-markdown-content .sl-link-button:where(.astro-5v627irg):not(:where(p *)){margin-block:1rem}} 38</style>
38<script type="module" src="/_astro/page.DJvz4Mfu.js"></script>
38</head> <body class="astro-lkmsl3sa"> <a href="#_top" class="astro-n4s4e6uq">Skip to content</a> <div class="page sl-flex astro-nspgss52"> <header class="header astro-nspgss52"><div class="header astro-2bzkuzuh"> <div class="title-wrapper sl-flex astro-2bzkuzuh"> <a href="/" class="site-title sl-flex astro-litqodtp"> <img class="light:sl-hidden print:hidden astro-litqodtp" alt src="/_astro/pgflow-logo-dark.BuQDBcad.svg" width="48" height="48"> <img class="dark:sl-hidden print:block astro-litqodtp" alt src="/_astro/pgflow-logo-light.BO9Ty74m.svg" width="48" height="48"> <span class="sr-only astro-litqodtp" translate="no"> pgflow (Workflow Engine for Supabase) </span> </a> </div> <div class="sl-flex print:hidden astro-2bzkuzuh"> <site-search class="astro-2bzkuzuh astro-hmexjgs7" data-translations="{"placeholder":"Search"}"> <button data-open-modal disabled aria-label="Search" aria-keyshortcuts="Control+K" class="astro-hmexjgs7"> <svg aria-hidden="true" class="astro-hmexjgs7 astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M21.71 20.29 18 16.61A9 9 0 1 0 16.61 18l3.68 3.68a.999.999 0 0 0 1.42 0 1 1 0 0 0 0-1.39ZM11 18a7 7 0 1 1 0-14 7 7 0 0 1 0 14Z"/></svg> <span class="sl-hidden md:sl-block astro-hmexjgs7" aria-hidden="true">Search</span> <kbd class="sl-hidden md:sl-flex astro-hmexjgs7" style="display: none;"> <kbd class="astro-hmexjgs7">Ctrl</kbd><kbd class="astro-hmexjgs7">K</kbd> </kbd> </button> <dialog style="padding:0" aria-label="Search" class="astro-hmexjgs7"> <div class="dialog-frame sl-flex astro-hmexjgs7"> <button data-close-modal class="sl-flex md:sl-hidden astro-hmexjgs7"> Cancel </button> <div class="search-container astro-hmexjgs7"> <div id="starlight__search" class="astro-hmexjgs7"></div> </div> </div> </dialog> </site-search>
38<script> 39 (() => { 40 const openBtn = document.querySelector('button[data-open-modal]'); 41 const shortcut = openBtn?.querySelector('kbd'); 42 if (!openBtn || !(shortcut instanceof HTMLElement)) return; 43 const platformKey = shortcut.querySelector('kbd'); 44 if (platformKey && /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform)) { 45 platformKey.textContent = 'â'; 46 openBtn.setAttribute('aria-keyshortcuts', 'Meta+K'); 47 } 48 shortcut.style.display = ''; 49 })(); 50</script>
50
50<script type="module" src="/_astro/Search.astro_astro_type_script_index_0_lang.cjYDvRdi.js"></script>
50 </div> <div class="sl-hidden md:sl-flex print:hidden right-group astro-2bzkuzuh"> <div class="sl-flex social-icons astro-2bzkuzuh"> <a href="https://github.com/pgflow-dev/pgflow" rel="me" class="sl-flex astro-d24x6kmv"><span class="sr-only astro-d24x6kmv">GitHub</span><svg aria-hidden="true" class="astro-d24x6kmv astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M12 .3a12 12 0 0 0-3.8 23.38c.6.12.83-.26.83-.57L9 21.07c-3.34.72-4.04-1.61-4.04-1.61-.55-1.39-1.34-1.76-1.34-1.76-1.08-.74.09-.73.09-.73 1.2.09 1.83 1.24 1.83 1.24 1.08 1.83 2.81 1.3 3.5 1 .1-.78.42-1.31.76-1.61-2.67-.3-5.47-1.33-5.47-5.93 0-1.31.47-2.38 1.24-3.22-.14-.3-.54-1.52.1-3.18 0 0 1-.32 3.3 1.23a11.5 11.5 0 0 1 6 0c2.28-1.55 3.29-1.23 3.29-1.23.64 1.66.24 2.88.12 3.18a4.65 4.65 0 0 1 1.23 3.22c0 4.61-2.8 5.63-5.48 5.92.42.36.81 1.1.81 2.22l-.01 3.29c0 .31.2.69.82.57A12 12 0 0 0 12 .3Z"/></svg></a><a href="https://x.com/pgflow_dev" rel="me" class="sl-flex astro-d24x6kmv"><span class="sr-only astro-d24x6kmv">X/Twitter</span><svg aria-hidden="true" class="astro-d24x6kmv astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M24 4.4a10 10 0 0 1-2.83.78 5.05 5.05 0 0 0 2.17-2.79 9.7 9.7 0 0 1-3.13 1.23 4.89 4.89 0 0 0-5.94-1.03 5 5 0 0 0-2.17 2.38 5.15 5.15 0 0 0-.3 3.25c-1.95-.1-3.86-.63-5.61-1.53a14.04 14.04 0 0 1-4.52-3.74 5.2 5.2 0 0 0-.09 4.91c.39.74.94 1.35 1.61 1.82a4.77 4.77 0 0 1-2.23-.63v.06c0 1.16.4 2.29 1.12 3.18a4.9 4.9 0 0 0 2.84 1.74c-.73.22-1.5.26-2.24.12a4.89 4.89 0 0 0 4.59 3.49A9.78 9.78 0 0 1 0 19.73 13.65 13.65 0 0 0 7.55 22a13.63 13.63 0 0 0 9.96-4.16A14.26 14.26 0 0 0 21.6 7.65V7c.94-.72 1.75-1.6 2.4-2.6Z"/></svg></a><a href="https://pgflow.dev/discord/" rel="me" class="sl-flex astro-d24x6kmv"><span class="sr-only astro-d24x6kmv">Discord</span><svg aria-hidden="true" class="astro-d24x6kmv astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M20.32 4.37a19.8 19.8 0 0 0-4.93-1.51 13.78 13.78 0 0 0-.64 1.28 18.27 18.27 0 0 0-5.5 0 12.64 12.64 0 0 0-.64-1.28h-.05A19.74 19.74 0 0 0 3.64 4.4 20.26 20.26 0 0 0 .11 18.09l.02.02a19.9 19.9 0 0 0 6.04 3.03l.04-.02a14.24 14.24 0 0 0 1.23-2.03.08.08 0 0 0-.05-.07 13.1 13.1 0 0 1-1.9-.92.08.08 0 0 1 .02-.1 10.2 10.2 0 0 0 .41-.31h.04a14.2 14.2 0 0 0 12.1 0l.04.01a9.63 9.63 0 0 0 .4.32.08.08 0 0 1-.03.1 12.29 12.29 0 0 1-1.9.91.08.08 0 0 0-.02.1 15.97 15.97 0 0 0 1.27 2.01h.04a19.84 19.84 0 0 0 6.03-3.05v-.03a20.12 20.12 0 0 0-3.57-13.69ZM8.02 15.33c-1.18 0-2.16-1.08-2.16-2.42 0-1.33.96-2.42 2.16-2.42 1.21 0 2.18 1.1 2.16 2.42 0 1.34-.96 2.42-2.16 2.42Zm7.97 0c-1.18 0-2.15-1.08-2.15-2.42 0-1.33.95-2.42 2.15-2.42 1.22 0 2.18 1.1 2.16 2.42 0 1.34-.94 2.42-2.16 2.42Z"/></svg></a><a href="/cdn-cgi/l/email-protection#d2bab7bebebd92a2b5b4bebda5fcb6b7a4" rel="me" class="sl-flex astro-d24x6kmv"><span class="sr-only astro-d24x6kmv">Contact author</span><svg aria-hidden="true" class="astro-d24x6kmv astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M19 4H5a3 3 0 0 0-3 3v10a3 3 0 0 0 3 3h14a3 3 0 0 0 3-3V7a3 3 0 0 0-3-3Zm-.41 2-5.88 5.88a1 1 0 0 1-1.42 0L5.41 6ZM20 17a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7.41l5.88 5.88a3 3 0 0 0 4.24 0L20 7.41Z"/></svg></a><a href="https://www.pgflow.dev/news/rss.xml" rel="me" class="sl-flex astro-d24x6kmv"><span class="sr-only astro-d24x6kmv">RSS</span><svg aria-hidden="true" class="astro-d24x6kmv astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M2.88 16.88a3 3 0 0 0 0 4.24 3 3 0 0 0 4.24 0 3 3 0 0 0-4.24-4.24Zm2.83 2.83a1 1 0 0 1-1.42-1.42 1 1 0 0 1 1.42 0 1 1 0 0 1 0 1.42ZM5 12a1 1 0 0 0 0 2 5 5 0 0 1 5 5 1 1 0 0 0 2 0 7 7 0 0 0-7-7Zm0-4a1 1 0 0 0 0 2 9 9 0 0 1 9 9 1 1 0 0 0 2 0 11.08 11.08 0 0 0-3.22-7.78A11.08 11.08 0 0 0 5 8Zm10.61.39A15.11 15.11 0 0 0 5 4a1 1 0 0 0 0 2 13 13 0 0 1 13 13 1 1 0 0 0 2 0 15.11 15.11 0 0 0-4.39-10.61Z"/></svg></a> </div> <div class="astro-3nauopy5"> <a href="/news/" class="astro-3nauopy5">News</a> </div> <starlight-theme-select> <label style="--sl-select-width: 6.25em" class="astro-ozffonnq"> <span class="sr-only astro-ozffonnq">Select theme</span> <svg aria-hidden="true" class="icon label-icon astro-ozffonnq astro-i27iqf3l" width="16" height="16" viewB
50ox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M21 14h-1V7a3 3 0 0 0-3-3H7a3 3 0 0 0-3 3v7H3a1 1 0 0 0-1 1v2a3 3 0 0 0 3 3h14a3 3 0 0 0 3-3v-2a1 1 0 0 0-1-1ZM6 7a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v7H6V7Zm14 10a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-1h16v1Z"/></svg> <select value="auto" autocomplete="off" class="astro-ozffonnq"> <option value="dark" class="astro-ozffonnq">Dark</option><option value="light" class="astro-ozffonnq">Light</option><option value="auto" selected class="astro-ozffonnq">Auto</option> </select> <svg aria-hidden="true" class="icon caret astro-ozffonnq astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M17 9.17a1 1 0 0 0-1.41 0L12 12.71 8.46 9.17a1 1 0 1 0-1.41 1.42l4.24 4.24a1.002 1.002 0 0 0 1.42 0L17 10.59a1.002 1.002 0 0 0 0-1.42Z"/></svg> </label> </starlight-theme-select>
vendor: 110 bytes, line 50
50 <script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script>
50<script> 51 StarlightThemeProvider.updatePickers(); 52</script>
52
52<script type="module">const r="starlight-theme",o=e=>e==="auto"||e==="dark"||e==="light"?e:"auto",c=()=>o(typeof localStorage<"u"&&localStorage.getItem(r));function n(e){typeof localStorage<"u"&&localStorage.setItem(r,e==="light"||e==="dark"?e:"")}const l=()=>matchMedia("(prefers-color-scheme: light)").matches?"light":"dark";function t(e){StarlightThemeProvider.updatePickers(e),document.documentElement.dataset.theme=e==="auto"?l():e,n(e)}matchMedia("(prefers-color-scheme: light)").addEventListener("change",()=>{c()==="auto"&&t("auto")});class s extends HTMLElement{constructor(){super(),t(c()),this.querySelector("select")?.addEventListener("change",a=>{a.currentTarget instanceof HTMLSelectElement&&t(o(a.currentTarget.value))})}}customElements.define("starlight-theme-select",s);</script>
52
52<script type="module">class s extends HTMLElement{constructor(){super();const e=this.querySelector("select");e&&(e.addEventListener("change",t=>{t.currentTarget instanceof HTMLSelectElement&&(window.location.pathname=t.currentTarget.value)}),window.addEventListener("pageshow",t=>{if(!t.persisted)return;const n=e.querySelector("option[selected]")?.index;n!==e.selectedIndex&&(e.selectedIndex=n??0)}))}}customElements.define("starlight-lang-select",s);</script>
52 </div> </div> </header> <nav class="sidebar print:hidden astro-nspgss52" aria-label="Main"> <starlight-menu-button class="print:hidden astro-zwz2cmvw"> <button aria-expanded="false" aria-label="Menu" aria-controls="starlight__sidebar" class="sl-flex md:sl-hidden astro-zwz2cmvw"> <svg aria-hidden="true" class="open-menu astro-zwz2cmvw astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M3 8h18a1 1 0 1 0 0-2H3a1 1 0 0 0 0 2Zm18 8H3a1 1 0 0 0 0 2h18a1 1 0 0 0 0-2Zm0-5H3a1 1 0 0 0 0 2h18a1 1 0 0 0 0-2Z"/></svg> <svg aria-hidden="true" class="close-menu astro-zwz2cmvw astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="m13.41 12 6.3-6.29a1.004 1.004 0 1 0-1.42-1.42L12 10.59l-6.29-6.3a1.004 1.004 0 0 0-1.42 1.42l6.3 6.29-6.3 6.29a1 1 0 0 0 0 1.42.998.998 0 0 0 1.42 0l6.29-6.3 6.29 6.3a.999.999 0 0 0 1.42 0 1 1 0 0 0 0-1.42L13.41 12Z"/></svg> </button> </starlight-menu-button>
52<script type="module">class s extends HTMLElement{constructor(){super(),this.btn=this.querySelector("button"),this.btn.addEventListener("click",()=>this.toggleExpanded());const t=this.closest("nav");t&&t.addEventListener("keyup",e=>this.closeOnEscape(e))}setExpanded(t){this.setAttribute("aria-expanded",String(t)),document.body.toggleAttribute("data-mobile-menu-expanded",t)}toggleExpanded(){this.setExpanded(this.getAttribute("aria-expanded")!=="true")}closeOnEscape(t){t.code==="Escape"&&(this.setExpanded(!1),this.btn.focus())}}customElements.define("starlight-menu-button",s);</script>
52 <div id="starlight__sidebar" class="sidebar-pane astro-nspgss52"> <div class="sidebar-content sl-flex astro-nspgss52"> <ul class="starlight-sidebar-topics astro-bsjuwxl3"> <li class="astro-bsjuwxl3"> <a href="/get-started/installation/" class="astro-bsjuwxl3"> <div class="starlight-sidebar-topics-icon astro-bsjuwxl3"> <svg aria-hidden="true" class="astro-bsjuwxl3 astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path fill-rule="evenodd" d="M1.44 8.855v-.001l3.527-3.516c.34-.344.802-.541 1.285-.548h6.649l.947-.947c3.07-3.07 6.207-3.072 7.62-2.868a1.821 1.821 0 0 1 1.557 1.557c.204 1.413.203 4.55-2.868 7.62l-.946.946v6.649a1.845 1.845 0 0 1-.549 1.286l-3.516 3.528a1.844 1.844 0 0 1-3.11-.944l-.858-4.275-4.52-4.52-2.31-.463-1.964-.394A1.847 1.847 0 0 1 .98 10.693a1.843 1.843 0 0 1 .46-1.838Zm5.379 2.017-3.873-.776L6.32 6.733h4.638l-4.14 4.14Zm8.403-5.655c2.459-2.46 4.856-2.463 5.89-2.33.134 1.035.13 3.432-2.329 5.891l-6.71 6.71-3.561-3.56 6.71-6.711Zm-1.318 15.837-.776-3.873 4.14-4.14v4.639l-3.364 3.374Z" clip-rule="evenodd"/><path d="M9.318 18.345a.972.972 0 0 0-1.86-.561c-.482 1.435-1.687 2.204-2.934 2.619a8.22 8.22 0 0 1-1.23.302c.062-.365.157-.79.303-1.229.415-1.247 1.184-2.452 2.62-2.935a.971.971 0 1 0-.62-1.842c-.12.04-.236.084-.35.13-2.02.828-3.012 2.588-3.493 4.033a10.383 10.383 0 0 0-.51 2.845l-.001.016v.063c0 .536.434.972.97.972H2.24a7.21 7.21 0 0 0 .878-.065c.527-.063 1.248-.19 2.02-.447 1.445-.48 3.205-1.472 4.033-3.494a5.828 5.828 0 0 0 .147-.407Z"/></svg> </div> <div class="astro-bsjuwxl3"> Get Started </div> </a> </li><li class="astro-bsjuwxl3"> <a href="/build/" class="astro-bsjuwxl3"> <div class="starlight-sidebar-topics-icon astro-bsjuwxl3"> <svg aria-hidden="true" class="astro-bsjuwxl3 astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M22 7.24a1 1 0 0 0-.29-.71l-4.24-4.24a1 1 0 0 0-1.1-.22 1 1 0 0 0-.32.22l-2.83 2.83L2.29 16.05a1 1 0 0 0-.29.71V21a1 1 0 0 0 1 1h4.24a1 1 0 0 0 .76-.29l10.87-10.93L21.71 8c.1-.1.17-.2.22-.33a1 1 0 0 0 0-.24v-.14l.07-.05ZM6.83 20H4v-2.83l9.93-9.93 2.83 2.83L6.83 20ZM18.17 8.66l-2.83-2.83 1.42-1.41 2.82 2.82-1.41 1.42Z"/></svg> </div> <div class="astro-bsjuwxl3"> Build </div> </a> </li><li class="astro-bsjuwxl3"> <a href="/deploy/" class="astro-bsjuwxl3"> <div class="starlight-sidebar-topics-icon astro-bsjuwxl3"> <svg aria-hidden="true" class="astro-bsjuwxl3 astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M14.29 17.29 13 18.59V13a1 1 0 0 0-2 0v5.59l-1.29-1.3a1 1 0 0 0-1.42 1.42l3 3a1 1 0 0 0 .33.21.94.94 0 0 0 .76 0 1 1 0 0 0 .33-.21l3-3a1 1 0 0 0-1.42-1.42Zm4.13-11.07A7 7 0 0 0 5.06 8.11 4 4 0 0 0 6 16a1 1 0 0 0 0-2 2 2 0 0 1 0-4 1 1 0 0 0 1-1 5 5 0 0 1 9.73-1.61 1 1 0 0 0 .78.67 3 3 0 0 1 .24 5.84 1 1 0 1 0 .5 1.94 5 5 0 0 0 .17-9.62Z"/></svg> </div> <div class="astro-bsjuwxl3"> Deploy </div> </a> </li><li class="astro-bsjuwxl3"> <a href="/concepts/" class="starlight-sidebar-topics-current astro-bsjuwxl3"> <div class="starlight-sidebar-topics-icon astro-bsjuwxl3"> <svg aria-hidden="true" class="astro-bsjuwxl3 astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M17 22H5a3 3 0 0 1-3-3V9a3 3 0 0 1 3-3h1a4 4 0 0 1 7.3-2.18c.448.64.692 1.4.7 2.18h3a1 1 0 0 1 1 1v3a4 4 0 0 1 2.18 7.3A3.86 3.86 0 0 1 18 18v3a1 1 0 0 1-1 1ZM5 8a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h11v-3.18a1 1 0 0 1 1.33-.95 1.77 1.77 0 0 0 1.74-.23 2 2 0 0 0 .93-1.37 2 2 0 0 0-.48-1.59 1.89 1.89 0 0 0-2.17-.55 1 1 0 0 1-1.33-.95V8h-3.2a1 1 0 0 1-1-1.33 1.77 1.77 0 0 0-.23-1.74 1.939 1.939 0 0 0-3-.43A2 2 0 0 0 8 6c.002.23.046.456.13.67A1 1 0 0 1 7.18 8H5Z"/></svg> </div> <div class="astro-bsjuwxl3"> Concepts </div> </a> </li><li class="astro-bsjuwxl3"> <a href="/reference/" class="astro-bsjuwxl3"> <div class="starlight-sidebar-topics-icon astro-bsjuwxl3"> <svg aria-hidden="true" class="astro-bsjuwxl3 astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M9 10h1a1 1 0 1 0 0-2H9a1 1 0 0 0 0 2Zm0 2a1 1 0 0 0 0 2h6a1 1 0 0 0 0-2H9Zm11-3.06a1.3 1.3 0 0 0-.06-.27v-.09c-.05-.1-.11-.2-.19-.28l-6-6a1.07 1.07 0 0 0-.28-.19h-.09a.88.88 0 0 0-.33-.11H7a3 3 0 0 0-3 3v14a3 3 0 0 0 3 3h10a3 3 0 0 0 3-3V8.94Zm-6-3.53L16.59 8H15a1 1 0 0 1-1-1V5.41ZM18 19a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h5v3a3 3 0 0 0 3 3h3v9Zm-3-3H9a1 1 0 0 0 0 2h6a1 1 0 0 0 0-2Z"/></svg> </div> <div class="astro-bsjuwxl3"> Reference </div> </a> </li><li class="astro-bsjuwxl3"> <a href="/tutorials/" class="astro-bsjuwxl3"> <div class="starlight-sidebar-topics-icon astro-bsjuwxl3"> <svg aria-hidden="true" class="astro-bsjuwxl3 astro-i27iqf3l" width="16" height="16" viewB
52ox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M21.17 2.06A13.1 13.1 0 0 0 19 1.87a12.94 12.94 0 0 0-7 2.05 12.94 12.94 0 0 0-7-2 13.1 13.1 0 0 0-2.17.19 1 1 0 0 0-.83 1v12a1 1 0 0 0 1.17 1 10.9 10.9 0 0 1 8.25 1.91l.12.07h.11a.91.91 0 0 0 .7 0h.11l.12-.07A10.899 10.899 0 0 1 20.83 16 1 1 0 0 0 22 15V3a1 1 0 0 0-.83-.94ZM11 15.35a12.87 12.87 0 0 0-6-1.48H4v-10c.333-.02.667-.02 1 0a10.86 10.86 0 0 1 6 1.8v9.68Zm9-1.44h-1a12.87 12.87 0 0 0-6 1.48V5.67a10.86 10.86 0 0 1 6-1.8c.333-.02.667-.02 1 0v10.04Zm1.17 4.15a13.098 13.098 0 0 0-2.17-.19 12.94 12.94 0 0 0-7 2.05 12.94 12.94 0 0 0-7-2.05c-.727.003-1.453.066-2.17.19A1 1 0 0 0 2 19.21a1 1 0 0 0 1.17.79 10.9 10.9 0 0 1 8.25 1.91 1 1 0 0 0 1.16 0A10.9 10.9 0 0 1 20.83 20a1 1 0 0 0 1.17-.79 1 1 0 0 0-.83-1.15Z"/></svg> </div> <div class="astro-bsjuwxl3"> Tutorials </div> </a> </li><li class="astro-bsjuwxl3"> <a href="/comparisons/" class="astro-bsjuwxl3"> <div class="starlight-sidebar-topics-icon astro-bsjuwxl3"> <svg aria-hidden="true" class="astro-bsjuwxl3 astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M8.7 10a1 1 0 0 0 1.41 0 1 1 0 0 0 0-1.41l-6.27-6.3a1 1 0 0 0-1.42 1.42ZM21 14a1 1 0 0 0-1 1v3.59L15.44 14A1 1 0 0 0 14 15.44L18.59 20H15a1 1 0 0 0 0 2h6a1 1 0 0 0 .38-.08 1 1 0 0 0 .54-.54A1 1 0 0 0 22 21v-6a1 1 0 0 0-1-1Zm.92-11.38a1 1 0 0 0-.54-.54A1 1 0 0 0 21 2h-6a1 1 0 0 0 0 2h3.59L2.29 20.29a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0L20 5.41V9a1 1 0 0 0 2 0V3a1 1 0 0 0-.08-.38Z"/></svg> </div> <div class="astro-bsjuwxl3"> Comparisons </div> </a> </li> </ul> <sl-sidebar-state-persist data-hash="196p1tg" class="astro-yuwwt5no">
52<script aria-hidden="true"> 53 (() => { 54 try { 55 if (!matchMedia('(min-width: 50em)').matches) return; 56 /** @type {HTMLElement | null} */ 57 const target = document.querySelector('sl-sidebar-state-persist'); 58 const state = JSON.parse(sessionStorage.getItem('sl-sidebar-state') || '0'); 59 if (!target || !state || target.dataset.hash !== state.hash) return; 60 window._starlightScrollRestore = state.scroll; 61 customElements.define( 62 'sl-sidebar-restore', 63 class SidebarRestore extends HTMLElement { 64 connectedCallback() { 65 try { 66 const idx = parseInt(this.dataset.index || ''); 67 const details = this.closest('details'); 68 if (details && typeof state.open[idx] === 'boolean') details.open = state.open[idx]; 69 } catch {} 70 } 71 } 72 ); 73 } catch {} 74 })(); 75 </script>
75 <ul class="top-level astro-zy72yfpm"> <li class="astro-zy72yfpm"> <a href="/news/" aria-current="false" class="large sl-blog-mobile-link astro-zy72yfpm" class="sl-blog-mobile-link"> <span class="astro-zy72yfpm">News</span> </a> </li><li class="astro-zy72yfpm"> <a href="/concepts/" aria-current="false" class="large astro-zy72yfpm"> <span class="astro-zy72yfpm">Overview</span> </a> </li><li class="astro-zy72yfpm"> <details open class="astro-zy72yfpm"> <sl-sidebar-restore data-index="0"></sl-sidebar-restore> <summary class="astro-zy72yfpm"> <div class="group-label astro-zy72yfpm"> <span class="large astro-zy72yfpm">Architecture</span> </div> <svg aria-hidden="true" class="caret astro-zy72yfpm astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.25rem;"><path d="m14.83 11.29-4.24-4.24a1 1 0 1 0-1.42 1.41L12.71 12l-3.54 3.54a1 1 0 0 0 0 1.41 1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.24-4.24a1.002 1.002 0 0 0 0-1.42Z"/></svg> </summary> <ul class="astro-zy72yfpm"> <li class="astro-zy72yfpm"> <a href="/concepts/how-pgflow-works/" aria-current="page" class="astro-zy72yfpm"> <span class="astro-zy72yfpm">How pgflow works</span> </a> </li><li class="astro-zy72yfpm"> <a href="/concepts/three-layer-architecture/" aria-current="false" class="astro-zy72yfpm"> <span class="astro-zy72yfpm">Three-layer architecture</span> </a> </li><li class="astro-zy72yfpm"> <a href="/concepts/data-model/" aria-current="false" class="astro-zy72yfpm"> <span class="astro-zy72yfpm">Data model</span> </a> </li><li class="astro-zy72yfpm"> <a href="/concepts/failures-and-termination/" aria-current="false" class="astro-zy72yfpm"> <span class="astro-zy72yfpm">Failures and termination</span> </a> </li><li class="astro-zy72yfpm"> <a href="/concepts/startup-compilation/" aria-current="false" class="astro-zy72yfpm"> <span class="astro-zy72yfpm">Startup Compilation</span> </a> </li><li class="astro-zy72yfpm"> <a href="/concepts/worker-lifecycle/" aria-current="false" class="astro-zy72yfpm"> <span class="astro-zy72yfpm">Worker lifecycle</span> </a> </li> </ul> </details> </li><li class="astro-zy72yfpm"> <details open class="astro-zy72yfpm"> <sl-sidebar-restore data-index="1"></sl-sidebar-restore> <summary class="astro-zy72yfpm"> <div class="group-label astro-zy72yfpm"> <span class="large astro-zy72yfpm">Defining Flows</span> </div> <svg aria-hidden="true" class="caret astro-zy72yfpm astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.25rem;"><path d="m14.83 11.29-4.24-4.24a1 1 0 1 0-1.42 1.41L12.71 12l-3.54 3.54a1 1 0 0 0 0 1.41 1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.24-4.24a1.002 1.002 0 0 0 0-1.42Z"/></svg> </summary> <ul class="astro-zy72yfpm"> <li class="astro-zy72yfpm"> <a href="/concepts/understanding-flows/" aria-current="false" class="astro-zy72yfpm"> <span class="astro-zy72yfpm">Understanding flows</span> </a> </li><li class="astro-zy72yfpm"> <a href="/concepts/map-steps/" aria-current="false" class="astro-zy72yfpm"> <span class="astro-zy72yfpm">Map steps</span> </a> </li><li class="astro-zy72yfpm"> <a href="/concepts/context-object/" aria-current="false" class="astro-zy72yfpm"> <span class="astro-zy72yfpm">Context object</span> </a> </li><li class="astro-zy72yfpm"> <a href="/concepts/naming-conventions/" aria-current="false" class="astro-zy72yfpm"> <span class="astro-zy72yfpm">Naming conventions</span> </a> </li> </ul> </details> </li> </ul>
75<script aria-hidden="true"> 76 (() => { 77 const scroller = document.getElementById('starlight__sidebar'); 78 if (!window._starlightScrollRestore || !scroller) return; 79 scroller.scrollTop = window._starlightScrollRestore; 80 delete window._starlightScrollRestore; 81 })(); 82 </script>
82 </sl-sidebar-state-persist> <div class="md:sl-hidden"> <div class="mobile-preferences sl-flex astro-ermroiay"> <div class="social-icons astro-ermroiay"> <a href="https://github.com/pgflow-dev/pgflow" rel="me" class="sl-flex astro-d24x6kmv"><span class="sr-only astro-d24x6kmv">GitHub</span><svg aria-hidden="true" class="astro-d24x6kmv astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M12 .3a12 12 0 0 0-3.8 23.38c.6.12.83-.26.83-.57L9 21.07c-3.34.72-4.04-1.61-4.04-1.61-.55-1.39-1.34-1.76-1.34-1.76-1.08-.74.09-.73.09-.73 1.2.09 1.83 1.24 1.83 1.24 1.08 1.83 2.81 1.3 3.5 1 .1-.78.42-1.31.76-1.61-2.67-.3-5.47-1.33-5.47-5.93 0-1.31.47-2.38 1.24-3.22-.14-.3-.54-1.52.1-3.18 0 0 1-.32 3.3 1.23a11.5 11.5 0 0 1 6 0c2.28-1.55 3.29-1.23 3.29-1.23.64 1.66.24 2.88.12 3.18a4.65 4.65 0 0 1 1.23 3.22c0 4.61-2.8 5.63-5.48 5.92.42.36.81 1.1.81 2.22l-.01 3.29c0 .31.2.69.82.57A12 12 0 0 0 12 .3Z"/></svg></a><a href="https://x.com/pgflow_dev" rel="me" class="sl-flex astro-d24x6kmv"><span class="sr-only astro-d24x6kmv">X/Twitter</span><svg aria-hidden="true" class="astro-d24x6kmv astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M24 4.4a10 10 0 0 1-2.83.78 5.05 5.05 0 0 0 2.17-2.79 9.7 9.7 0 0 1-3.13 1.23 4.89 4.89 0 0 0-5.94-1.03 5 5 0 0 0-2.17 2.38 5.15 5.15 0 0 0-.3 3.25c-1.95-.1-3.86-.63-5.61-1.53a14.04 14.04 0 0 1-4.52-3.74 5.2 5.2 0 0 0-.09 4.91c.39.74.94 1.35 1.61 1.82a4.77 4.77 0 0 1-2.23-.63v.06c0 1.16.4 2.29 1.12 3.18a4.9 4.9 0 0 0 2.84 1.74c-.73.22-1.5.26-2.24.12a4.89 4.89 0 0 0 4.59 3.49A9.78 9.78 0 0 1 0 19.73 13.65 13.65 0 0 0 7.55 22a13.63 13.63 0 0 0 9.96-4.16A14.26 14.26 0 0 0 21.6 7.65V7c.94-.72 1.75-1.6 2.4-2.6Z"/></svg></a><a href="https://pgflow.dev/discord/" rel="me" class="sl-flex astro-d24x6kmv"><span class="sr-only astro-d24x6kmv">Discord</span><svg aria-hidden="true" class="astro-d24x6kmv astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M20.32 4.37a19.8 19.8 0 0 0-4.93-1.51 13.78 13.78 0 0 0-.64 1.28 18.27 18.27 0 0 0-5.5 0 12.64 12.64 0 0 0-.64-1.28h-.05A19.74 19.74 0 0 0 3.64 4.4 20.26 20.26 0 0 0 .11 18.09l.02.02a19.9 19.9 0 0 0 6.04 3.03l.04-.02a14.24 14.24 0 0 0 1.23-2.03.08.08 0 0 0-.05-.07 13.1 13.1 0 0 1-1.9-.92.08.08 0 0 1 .02-.1 10.2 10.2 0 0 0 .41-.31h.04a14.2 14.2 0 0 0 12.1 0l.04.01a9.63 9.63 0 0 0 .4.32.08.08 0 0 1-.03.1 12.29 12.29 0 0 1-1.9.91.08.08 0 0 0-.02.1 15.97 15.97 0 0 0 1.27 2.01h.04a19.84 19.84 0 0 0 6.03-3.05v-.03a20.12 20.12 0 0 0-3.57-13.69ZM8.02 15.33c-1.18 0-2.16-1.08-2.16-2.42 0-1.33.96-2.42 2.16-2.42 1.21 0 2.18 1.1 2.16 2.42 0 1.34-.96 2.42-2.16 2.42Zm7.97 0c-1.18 0-2.15-1.08-2.15-2.42 0-1.33.95-2.42 2.15-2.42 1.22 0 2.18 1.1 2.16 2.42 0 1.34-.94 2.42-2.16 2.42Z"/></svg></a><a href="/cdn-cgi/l/email-protection#365e535a5a59764651505a594118525340" rel="me" class="sl-flex astro-d24x6kmv"><span class="sr-only astro-d24x6kmv">Contact author</span><svg aria-hidden="true" class="astro-d24x6kmv astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M19 4H5a3 3 0 0 0-3 3v10a3 3 0 0 0 3 3h14a3 3 0 0 0 3-3V7a3 3 0 0 0-3-3Zm-.41 2-5.88 5.88a1 1 0 0 1-1.42 0L5.41 6ZM20 17a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7.41l5.88 5.88a3 3 0 0 0 4.24 0L20 7.41Z"/></svg></a><a href="https://www.pgflow.dev/news/rss.xml" rel="me" class="sl-flex astro-d24x6kmv"><span class="sr-only astro-d24x6kmv">RSS</span><svg aria-hidden="true" class="astro-d24x6kmv astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M2.88 16.88a3 3 0 0 0 0 4.24 3 3 0 0 0 4.24 0 3 3 0 0 0-4.24-4.24Zm2.83 2.83a1 1 0 0 1-1.42-1.42 1 1 0 0 1 1.42 0 1 1 0 0 1 0 1.42ZM5 12a1 1 0 0 0 0 2 5 5 0 0 1 5 5 1 1 0 0 0 2 0 7 7 0 0 0-7-7Zm0-4a1 1 0 0 0 0 2 9 9 0 0 1 9 9 1 1 0 0 0 2 0 11.08 11.08 0 0 0-3.22-7.78A11.08 11.08 0 0 0 5 8Zm10.61.39A15.11 15.11 0 0 0 5 4a1 1 0 0 0 0 2 13 13 0 0 1 13 13 1 1 0 0 0 2 0 15.11 15.11 0 0 0-4.39-10.61Z"/></svg></a> </div> <div class="astro-3nauopy5"> <a href="/news/" class="astro-3nauopy5">News</a> </div> <starlight-theme-select> <label style="--sl-select-width: 6.25em" class="astro-ozffonnq"> <span class="sr-only astro-ozffonnq">Select theme</span> <svg aria-hidden="true" class="icon label-icon astro-ozffonnq astro-i27iqf3l" width="16" height="16" viewB
82ox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M21 14h-1V7a3 3 0 0 0-3-3H7a3 3 0 0 0-3 3v7H3a1 1 0 0 0-1 1v2a3 3 0 0 0 3 3h14a3 3 0 0 0 3-3v-2a1 1 0 0 0-1-1ZM6 7a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v7H6V7Zm14 10a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-1h16v1Z"/></svg> <select value="auto" autocomplete="off" class="astro-ozffonnq"> <option value="dark" class="astro-ozffonnq">Dark</option><option value="light" class="astro-ozffonnq">Light</option><option value="auto" selected class="astro-ozffonnq">Auto</option> </select> <svg aria-hidden="true" class="icon caret astro-ozffonnq astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M17 9.17a1 1 0 0 0-1.41 0L12 12.71 8.46 9.17a1 1 0 1 0-1.41 1.42l4.24 4.24a1.002 1.002 0 0 0 1.42 0L17 10.59a1.002 1.002 0 0 0 0-1.42Z"/></svg> </label> </starlight-theme-select>
vendor: 110 bytes, line 82
82 <script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script>
82<script> 83 StarlightThemeProvider.updatePickers(); 84</script>
84 </div> </div> </div> </div> </nav> <div class="main-frame astro-nspgss52">
84<script type="module">const a=document.getElementById("starlight__sidebar"),n=a?.querySelector("sl-sidebar-state-persist"),o="sl-sidebar-state",i=()=>{let t=[];const e=n?.dataset.hash||"";try{const s=sessionStorage.getItem(o),r=JSON.parse(s||"{}");Array.isArray(r.open)&&r.hash===e&&(t=r.open)}catch{}return{hash:e,open:t,scroll:a?.scrollTop||0}},c=t=>{try{sessionStorage.setItem(o,JSON.stringify(t))}catch{}},d=()=>c(i()),l=(t,e)=>{const s=i();s.open[e]=t,c(s)};n?.addEventListener("click",t=>{if(!(t.target instanceof Element))return;const e=t.target.closest("summary")?.closest("details");if(!e)return;const s=e.querySelector("sl-sidebar-restore"),r=parseInt(s?.dataset.index||"");isNaN(r)||l(!e.open,r)});addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&d()});addEventListener("pageHide",d);</script>
84 <div class="lg:sl-flex astro-mndfwee4"> <aside class="right-sidebar-container print:hidden astro-mndfwee4"> <div class="right-sidebar astro-mndfwee4"> <div class="lg:sl-hidden astro-xvkfk6h2"><mobile-starlight-toc data-min-h="2" data-max-h="3" class="astro-mfxxoetl"><nav aria-labelledby="starlight__on-this-page--mobile" class="astro-mfxxoetl"><details id="starlight__mobile-toc" class="astro-mfxxoetl"><summary id="starlight__on-this-page--mobile" class="sl-flex astro-mfxxoetl"><div class="toggle sl-flex astro-mfxxoetl">On this page<svg aria-hidden="true" class="caret astro-mfxxoetl astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1rem;"><path d="m14.83 11.29-4.24-4.24a1 1 0 1 0-1.42 1.41L12.71 12l-3.54 3.54a1 1 0 0 0 0 1.41 1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.24-4.24a1.002 1.002 0 0 0 0-1.42Z"/></svg></div><span class="display-current astro-mfxxoetl"></span></summary><div class="dropdown astro-mfxxoetl"><ul class="isMobile astro-qdijszvq" style="--depth: 0;"> <li class="astro-qdijszvq" style="--depth: 0;"> <a href="#_top" class="astro-qdijszvq" style="--depth: 0;"> <span class="astro-qdijszvq" style="--depth: 0;">Overview</span> </a> </li><li class="astro-qdijszvq" style="--depth: 0;"> <a href="#how-pgflow-makes-this-possible" class="astro-qdijszvq" style="--depth: 0;"> <span class="astro-qdijszvq" style="--depth: 0;">How pgflow Makes This Possible</span> </a> </li><li class="astro-qdijszvq" style="--depth: 0;"> <a href="#from-code-to-execution" class="astro-qdijszvq" style="--depth: 0;"> <span class="astro-qdijszvq" style="--depth: 0;">From Code to Execution</span> </a> </li><li class="astro-qdijszvq" style="--depth: 0;"> <a href="#defining-the-workflow" class="astro-qdijszvq" style="--depth: 0;"> <span class="astro-qdijszvq" style="--depth: 0;">Defining the Workflow</span> </a> </li><li class="astro-qdijszvq" style="--depth: 0;"> <a href="#deploy-as-edge-function" class="astro-qdijszvq" style="--depth: 0;"> <span class="astro-qdijszvq" style="--depth: 0;">Deploy as Edge Function</span> </a> </li><li class="astro-qdijszvq" style="--depth: 0;"> <a href="#start-your-flow" class="astro-qdijszvq" style="--depth: 0;"> <span class="astro-qdijszvq" style="--depth: 0;">Start Your Flow</span> </a> </li><li class="astro-qdijszvq" style="--depth: 0;"> <a href="#learn-more" class="astro-qdijszvq" style="--depth: 0;"> <span class="astro-qdijszvq" style="--depth: 0;">Learn More</span> </a> </li> </ul> </div></details></nav></mobile-starlight-toc>
84<script type="module" src="/_astro/MobileTableOfContents.astro_astro_type_script_index_0_lang.C181hMzK.js"></script>
84</div><div class="right-sidebar-panel sl-hidden lg:sl-block astro-xvkfk6h2"><div class="sl-container astro-xvkfk6h2"><starlight-toc data-min-h="2" data-max-h="3"><nav aria-labelledby="starlight__on-this-page"><h2 id="starlight__on-this-page">On this page</h2><ul class="astro-qdijszvq" style="--depth: 0;"> <li class="astro-qdijszvq" style="--depth: 0;"> <a href="#_top" class="astro-qdijszvq" style="--depth: 0;"> <span class="astro-qdijszvq" style="--depth: 0;">Overview</span> </a> </li><li class="astro-qdijszvq" style="--depth: 0;"> <a href="#how-pgflow-makes-this-possible" class="astro-qdijszvq" style="--depth: 0;"> <span class="astro-qdijszvq" style="--depth: 0;">How pgflow Makes This Possible</span> </a> </li><li class="astro-qdijszvq" style="--depth: 0;"> <a href="#from-code-to-execution" class="astro-qdijszvq" style="--depth: 0;"> <span class="astro-qdijszvq" style="--depth: 0;">From Code to Execution</span> </a> </li><li class="astro-qdijszvq" style="--depth: 0;"> <a href="#defining-the-workflow" class="astro-qdijszvq" style="--depth: 0;"> <span class="astro-qdijszvq" style="--depth: 0;">Defining the Workflow</span> </a> </li><li class="astro-qdijszvq" style="--depth: 0;"> <a href="#deploy-as-edge-function" class="astro-qdijszvq" style="--depth: 0;"> <span class="astro-qdijszvq" style="--depth: 0;">Deploy as Edge Function</span> </a> </li><li class="astro-qdijszvq" style="--depth: 0;"> <a href="#start-your-flow" class="astro-qdijszvq" style="--depth: 0;"> <span class="astro-qdijszvq" style="--depth: 0;">Start Your Flow</span> </a> </li><li class="astro-qdijszvq" style="--depth: 0;"> <a href="#learn-more" class="astro-qdijszvq" style="--depth: 0;"> <span class="astro-qdijszvq" style="--depth: 0;">Learn More</span> </a> </li> </ul> </nav></starlight-toc>
84<script type="module" src="/_astro/TableOfContents.astro_astro_type_script_index_0_lang.CKWWgpjV.js"></script>
84</div></div> </div> </aside> <div class="main-pane astro-mndfwee4"> <main data-pagefind-body class="astro-lkmsl3sa" lang="en" dir="ltr"> <div class="content-panel astro-a6uhbnxq"> <div class="sl-container astro-a6uhbnxq"> <h1 id="_top" class="astro-ciolyesy">How pgflow Works</h1> </div> </div> <div class="content-panel astro-a6uhbnxq"> <div class="sl-container astro-a6uhbnxq"> <starlight-image-zoom> <template class="astro-soknys5x"> <dialog class="starlight-image-zoom-dialog astro-soknys5x"> <button aria-label="Unzoom image" class="starlight-image-zoom-control astro-soknys5x"> <svg aria-hidden="true" fill="currentColor" viewBox="0 0 24 24" class="astro-soknys5x"> <use href="#starlight-image-zoom-icon-unzoom" class="astro-soknys5x"></use> </svg> </button> <figure class="astro-soknys5x"></figure> </dialog> </template> <svg xmlns="http://www.w3.org/2000/svg" style="display:none" class="astro-soknys5x"> <symbol id="starlight-image-zoom-icon-zoom" viewBox="0 0 24 24" class="astro-soknys5x"> <path d="M9.79 12.79 4 18.59V17a1 1 0 0 0-2 0v4a1 1 0 0 0 .08.38 1 1 0 0 0 .54.54A1 1 0 0 0 3 22h4a1 1 0 0 0 0-2H5.41l5.8-5.79a1 1 0 0 0-1.42-1.42ZM21.92 2.62a1 1 0 0 0-.54-.54A1 1 0 0 0 21 2h-4a1 1 0 0 0 0 2h1.59l-5.8 5.79a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0L20 5.41V7a1 1 0 0 0 2 0V3a1 1 0 0 0-.08-.38Z" class="astro-soknys5x"></path> </symbol> <symbol id="starlight-image-zoom-icon-unzoom" viewBox="0 0 24 24" class="astro-soknys5x"> <path d="M21.71 2.29a1 1 0 0 0-1.42 0l-5.79 5.8V6.5a1 1 0 0 0-2 0v4a1 1 0 0 0 .08.38 1 1 0 0 0 .54.54 1 1 0 0 0 .38.08h4a1 1 0 0 0 0-2h-1.59l5.8-5.79a1 1 0 0 0 0-1.42ZM10.88 12.58a1 1 0 0 0-.38-.08h-4a1 1 0 0 0 0 2h1.59l-5.8 5.79a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l5.79-5.8v1.59a1 1 0 0 0 2 0v-4a1 1 0 0 0-.08-.38 1 1 0 0 0-.54-.54Z" class="astro-soknys5x"></path> </symbol> </svg> </starlight-image-zoom>
84<script type="module" src="/_astro/ImageZoom.astro_astro_type_script_index_0_lang.J1tlcSSG.js"></script>
84 <div class="sl-markdown-content"> <p>pgflow runs <strong>multi-step workflows</strong> (flows) on Supabase with automatic <strong>parallelization</strong>, <strong>retries</strong>, and <strong>dependency tracking</strong>. This page shows how it works.</p> 85<div class="animation-explainer"><div class="explainer-text"><p>This flow demonstrates three key behaviors:</p><p><strong>ð Parallel execution</strong> - <code dir="auto">summarize</code> and <code dir="auto">extractKeywords</code> start immediately after <code dir="auto">fetchArticle</code> completes.</p><p><strong>ð Automatic retry</strong> - When <code dir="auto">summarize</code> fails, pgflow retries automatically.</p><p><strong>ð Dependency coordination</strong> - <code dir="auto">publish</code> waits for both steps to complete.</p></div><div class="explainer-animation"><div class="hero-anim" id="flowDemo" data-anim-state="running" data-large="true" aria-describedby="flowDemoCaption flowDemoDetails"> <div class="animation-wrapper"> <button id="flowDemoToggle" type="button" aria-controls="flowDemoSvg" aria-pressed="true" title="Pause animation" class="anim-ctrl plausible-event-name=home:animation-pause">Pause</button> <div id="animation-container"></div> </div> <p id="flowDemoDetails" class="sr-only"> 86Two tasks run in parallel. One fails and automatically retries. After both succeed, they trigger the final publish step. 87</p> </div>
87<script> 88(function() { 89 // Animation state management 90 let timeoutIds = []; 91 let isPaused = false; 92 let svg = null; 93 94 function initAnimation() { 95 const container = document.getElementById('animation-container'); 96 if (!container) { 97 requestAnimationFrame(initAnimation); 98 return; 99 } 100 101 // Check if large variant 102 const heroAnim = document.getElementById('flowDemo'); 103 const isLarge = heroAnim && heroAnim.getAttribute('data-large') === 'true'; 104 105 // SVG structure 106 svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); 107 svg.setAttribute('id', 'flowDemoSvg'); 108 svg.setAttribute('viewBox', '5 25 490 495'); 109 110 // Node dimensions - adjust based on variant 111 const nodeWidth = isLarge ? 220 : 185; 112 const nodeHeight = isLarge ? 70 : 60; 113 114 // Define nodes positions (x,y = center of node) - vertical layout with more spacing 115 const nodes = [ 116 { id: 'fetchArticle', x: 250, y: 100, label: 'fetchArticle' }, 117 { id: 'summarize', x: isLarge ? 120 : 140, y: 275, label: 'summarize' }, 118 { id: 'extractKeywords', x: isLarge ? 380 : 360, y: 275, label: 'extractKeywords' }, 119 { id: 'publish', x: 250, y: 450, label: 'publish' } 120 ]; 121 122 // Define edges 123 const edges = [ 124 { from: 'fetchArticle', to: 'summarize' }, 125 { from: 'fetchArticle', to: 'extractKeywords' }, 126 { from: 'summarize', to: 'publish' }, 127 { from: 'extractKeywords', to: 'publish' } 128 ]; 129 130 // Helper function to create smooth curved paths for vertical layout 131 function createVerticalPath(x1, y1, x2, y2) { 132 const path = []; 133 path.push('M ' + x1 + ' ' + y1); // Start 134 135 // Calculate control points for smooth bezier curve 136 const midY = (y1 + y2) / 2; 137 138 // For vertical flows, use cubic bezier for smooth curves 139 // Control point 1: below start point 140 const cp1x = x1; 141 const cp1y = midY; 142 143 // Control point 2: above end point 144 const cp2x = x2; 145 const cp2y = midY; 146 147 // Cubic bezier curve 148 path.push('C ' + cp1x + ' ' + cp1y + ', ' + cp2x + ' ' + cp2y + ', ' + x2 + ' ' + y2); 149 150 return path.join(' '); 151 } 152 153 // Draw edges (for vertical layout, connect bottom of source to top of target)
154 edges.forEach(edge => { 155 const fromNode = nodes.find(n => n.id === edge.from); 156 const toNode = nodes.find(n => n.id === edge.to); 157 158 // Start from bottom center of source node 159 const x1 = fromNode.x; 160 const y1 = fromNode.y + nodeHeight / 2; 161 162 // End at top center of target node 163 const x2 = toNode.x; 164 const y2 = toNode.y - nodeHeight / 2; 165 166 const path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); 167 path.setAttribute('class', 'edge'); 168 path.setAttribute('data-edge', edge.from + '-' + edge.to); 169 path.setAttribute('d', createVerticalPath(x1, y1, x2, y2)); 170 svg.appendChild(path); 171 }); 172 173 // Status emoji 174 const statusEmoji = { 175 pending: 'â¯', // horizontal ellipsis for waiting 176 running: 'â¶', // play icon for in progress 177 retrying: 'â»', // circled arrow for retry attempt 178 success: 'â', // checkmark 179 failed: 'â' // cross 180 }; 181 182 // Draw nodes 183 nodes.forEach(node => { 184 const g = document.createElementNS('http://www.w3.org/2000/svg', 'g'); 185 g.setAttribute('class', 'node pending'); 186 g.setAttribute('data-node', node.id); 187 188 const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect'); 189 rect.setAttribute('x', node.x - nodeWidth / 2); 190 rect.setAttribute('y', node.y - nodeHeight / 2); 191 rect.setAttribute('width', nodeWidth); 192 rect.setAttribute('height', nodeHeight); 193 rect.setAttribute('rx', 4); 194 rect.setAttribute('ry', 4); 195 196 const text = document.createElementNS('http://www.w3.org/2000/svg', 'text'); 197 text.setAttribute('x', node.x); 198 text.setAttribute('y', node.y); 199 text.setAttribute('data-label', node.label); 200 text.textContent = node.label + ' ' + statusEmoji.pending; 201 202 g.appendChild(rect); 203 g.appendChild(text); 204 svg.appendChild(g); 205 }); 206 207 container.appendChild(svg); 208 209 // Animation helpers 210 function setState(nodeId, state) { 211 const node = svg.querySelector('[data-node="' + nodeId + '"]'); 212 node.className.baseVal = 'node ' + state; 213 214 // Update text with appropriate emoji 215 const text = node.querySelector('text'); 216 const label = text.getAttribute('data-label'); 217 text.textContent = label + ' ' + statusEmoji[state]; 218 219 // Activate outgoing edges when node succeeds 220 if (state === 'success') { 221 activateOutgoingEdges(nodeId); 222 updateIncomingEdges(nodeId); 223 } 224 } 225 226 function activateOutgoingEdges(nodeId) { 227 // Find all edges that start from this node
228 edges.forEach(edge => { 229 if (edge.from === nodeId) { 230 const edgePath = svg.querySelector('[data-edge="' + edge.from + '-' + edge.to + '"]'); 231 if (edgePath) { 232 edgePath.classList.add('active'); 233 234 // Check if target node is also successful 235 const targetNode = svg.querySelector('[data-node="' + edge.to + '"]'); 236 if (targetNode && targetNode.className.baseVal.includes('success')) { 237 edgePath.classList.add('complete'); 238 } 239 } 240 } 241 }); 242 } 243 244 function updateIncomingEdges(nodeId) { 245 // When a node becomes successful, check all incoming edges 246 // and mark them as complete if their source is also successful 247 edges.forEach(edge => { 248 if (edge.to === nodeId) { 249 const edgePath = svg.querySelector('[data-edge="' + edge.from + '-' + edge.to + '"]'); 250 const sourceNode = svg.querySelector('[data-node="' + edge.from + '"]'); 251 252 if (edgePath && sourceNode && sourceNode.className.baseVal.includes('success')) { 253 edgePath.classList.add('complete'); 254 } 255 } 256 }); 257 } 258 259 // Animation timeline - optimized for hero section 260 const timeline = [ 261 { time: 0, action: () => setState('fetchArticle', 'running') }, 262 { time: 1320, action: () => setState('fetchArticle', 'success') }, 263 { time: 1540, action: () => { 264 setState('summarize', 'running'); 265 setState('extractKeywords', 'running'); 266 }}, 267 { time: 3080, action: () => setState('extractKeywords', 'success') }, 268 { time: 4180, action: () => setState('summarize', 'failed') }, 269 { time: 5500, action: () => setState('summarize', 'retrying') }, 270 { time: 7040, action: () => setState('summarize', 'success') }, 271 { time: 7260, action: () => setState('publish', 'running') }, 272 { time: 9020, action: () => setState('publish', 'success') } 273 ]; 274 275 function resetAnimation() { 276 // Reset all nodes to pending 277 setState('fetchArticle', 'pending'); 278 setState('summarize', 'pending'); 279 setState('extractKeywords', 'pending'); 280 setState('publish', 'pending'); 281 282 // Deactivate all edges 283 const allEdges = svg.querySelectorAll('.edge'); 284 allEdges.forEach(edge => { 285 edge.classList.remove('active', 'complete'); 286 }); 287 } 288 289 function clearAllTimeouts() { 290 timeoutIds.forEach(id => clearTimeout(id)); 291 timeoutIds = []; 292 } 293 294 function runAnimation() { 295 if (isPaused) return; 296 297 resetAnimation(); 298 clearAllTimeouts(); 299 300 timeline.forEach(({ time, action }) => { 301 const id = setTimeout(action, time); 302 timeoutIds.push(id); 303 }); 304 305 // Loop after 11 seconds 306 const loopId = setTimeout(runAnimation, 11000); 307 timeoutIds.push(loopId); 308 } 309 310 function pauseAnimation() { 311 isPaused = true; 312 clearAllTimeouts(); 313 } 314 315 function resumeAnimation() { 316 isPaused = false; 317 runAnimation(); 318 } 319 320 // Check for reduced-motion preference 321 const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches; 322 323 // Initialize toggle button 324 const toggle = document.getElementById('flowDemoToggle'); 325 326 if (prefersReducedMotion) { 327 isPaused = true; 328 toggle.setAttribute('aria-pressed', 'false'); 329 toggle.setAttribute('title', 'Restart animation'); 330 toggle.textContent = 'Restart'; 331 } 332 333 // Wire up toggle button 334 toggle.addEventListener('click', function() { 335 if (isPaused) { 336 resumeAnimation(); 337 toggle.setAttribute('aria-pressed', 'true'); 338 toggle.setAttribute('title', 'Pause animation'); 339 toggle.textContent = 'Pause'; 340 } else { 341 pauseAnimation(); 342 toggle.setAttribute('aria-pressed', 'false'); 343 toggle.setAttribute('title', 'Restart animation'); 344 toggle.textContent = 'Restart'; 345 } 346 }); 347 348 // Start animation (unless paused by reduced-motion preference) 349 if (!isPaused) { 350 runAnimation(); 351 } 352 } 353 354 initAnimation(); 355})(); 356</script>
356</div></div> 357<style> 358.animation-explainer { 359 display: grid; 360 grid-template-columns: 1fr 1fr; 361 gap: 1.5rem; 362 align-items: start; 363} 364 365.explainer-animation { 366 position: sticky; 367 top: 2rem; 368 margin-top: -1rem; 369} 370 371@media (max-width: 1024px) { 372 .animation-explainer { 373 grid-template-columns: 1fr; 374 gap: 2rem; 375 } 376 377 .explainer-text { 378 text-align: left; 379 } 380 381 .explainer-animation { 382 position: relative; 383 top: 0; 384 max-width: 100%; 385 width: 100%; 386 margin: 0; 387 overflow: hidden; 388 } 389} 390</style> 391<hr> 392<p>Now letâs understand what happens under the hood.</p> 393<div class="sl-heading-wrapper level-h2"><h2 id="how-pgflow-makes-this-possible">How pgflow Makes This Possible</h2><a class="sl-anchor-link" href="#how-pgflow-makes-this-possible"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24"><path fill="currentcolor" d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z"></path></svg></span><span class="sr-only">Section titled âHow pgflow Makes This Possibleâ</span></a></div> 394<p>At its core, pgflow does two things:</p> 395<ol> 396<li>ð§ <strong>Figures out</strong> which steps are ready based on dependencies</li> 397<li>ð¤ <strong>Pushes tasks</strong> into queues for workers to execute</li> 398</ol> 399<p>Workers pull from these queues and run your functions.</p> 400<aside aria-label="Key Separation" class="starlight-aside starlight-aside--note"> <p class="starlight-aside__title" aria-hidden="true"> <svg aria-hidden="true" class="starlight-aside__icon astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M12 11a1 1 0 0 0-1 1v4a1 1 0 0 0 2 0v-4a1 1 0 0 0-1-1Zm.38-3.92a1 1 0 0 0-.76 0 1 1 0 0 0-.33.21 1.15 1.15 0 0 0-.21.33 1 1 0 0 0 .21 1.09c.097.088.209.16.33.21A1 1 0 0 0 13 8a1.05 1.05 0 0 0-.29-.71 1 1 0 0 0-.33-.21ZM12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20Zm0 18a8 8 0 1 1 0-16.001A8 8 0 0 1 12 20Z"/></svg>Key Separation </p> <div class="starlight-aside__content"> <p><strong>pgflow</strong> handles orchestration (what to run, when)</p><p><strong>You</strong> handle business logic (how to process data)</p> </div> </aside> 401<hr> 402<div class="sl-heading-wrapper level-h2"><h2 id="from-code-to-execution">From Code to Execution</h2><a class="sl-anchor-link" href="#from-code-to-execution"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24"><path fill="currentcolor" d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z"></path></svg></span><span class="sr-only">Section titled âFrom Code to Executionâ</span></a></div> 403<p>ð¨ <strong>Definition-time</strong>: Write workflows in TypeScript; the worker compiles or verifies the definition in the database at startup (<a href="/concepts/startup-compilation/">startup compilation</a>)</p> 404<p>â¡ <strong>Run-time</strong>: Postgres orchestrates (determines what runs when), workers execute your functions</p> 405<p>All workflow state lives in Postgres tables - giving you full observability.</p> 406<hr> 407<div class="sl-heading-wrapper level-h2"><h2 id="defining-the-workflow">Defining the Workflow</h2><a class="sl-anchor-link" href="#defining-the-workflow"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24">
407<path fill="currentcolor" d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z"></path></svg></span><span class="sr-only">Section titled âDefining the Workflowâ</span></a></div> 408<p>Workflows are built by chaining <code dir="auto">.step()</code> calls. Each step has a unique <strong>slug</strong> (identifier) and declares which steps it <strong>dependsOn</strong>:</p> 409<div class="expressive-code"><link rel="stylesheet" href="/_astro/ec.v4551.css">
409<script type="module" src="/_astro/ec.p1z7b.js"></script>
409<figure class="frame not-content"><figcaption class="header"></figcaption><pre data-language="typescript"><code><div class="ec-line"><div class="code"><span style="--0:#7FDBCA;--1:#096E72">new</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#82AAFF;--1:#3B61B0">Flow</span><span style="--0:#D6DEEB;--1:#403F53"><</span><span style="--0:#FFCB8B;--1:#111111">Input</span><span style="--0:#D6DEEB;--1:#403F53">>({ slug: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">process_article</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53"> })</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#C792EA;--1:#8844AE">.</span><span style="--0:#82AAFF;--1:#3B61B0">step</span><span style="--0:#D6DEEB;--1:#403F53">({ slug: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">fetchArticle</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53"> }, fn)</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#C792EA;--1:#8844AE">.</span><span style="--0:#82AAFF;--1:#3B61B0">step</span><span style="--0:#D6DEEB;--1:#403F53">({ slug: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">summarize</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">, dependsOn: [</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">fetchArticle</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">] }, fn)</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#C792EA;--1:#8844AE">.</span><span style="--0:#82AAFF;--1:#3B61B0">step</span><span style="--0:#D6DEEB;--1:#403F53">({ slug: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">extractKeywords</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">, dependsOn: [</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">fetchArticle</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">] }, fn)</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#C792EA;--1:#8844AE">.</span><span style="--0:#82AAFF;--1:#3B61B0">step</span><span style="--0:#D6DEEB;--1:#403F53">({ slug: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">publish</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">, dependsOn: [</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">summarize</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">, </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">extractKeywords</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">] }, fn);</span></div></div></code></pre><div class="copy"><button title="Copy to clipboard" data-copied="Copied!" data-code="new Flow<Input>({ slug: "process_article" })� .step({ slug: "fetchArticle" }, fn)� .step({ slug: "summarize", dependsOn: ["fetchArticle"] }, fn)� .step({ slug: "extractKeywords", dependsOn: ["fetchArticle"] }, fn)� .step({ slug: "publish", dependsOn: ["summarize", "extractKeywords"] }, fn);"><div></div></button></div></figure></div> 410<p>pgflow uses dependencies to figure out execution order and parallelism. Steps with the same dependencies run in parallel. Return values become available as <code dir="auto">deps.<slug></code> to dependent steps.</p> 411<details><summary>See full code</summary><div class="expressive-code"><figure class="frame not-content"><figcaption class="header"></figcaption><pre data-language="typescript"><code><div class="ec-line"><div class="code"><span style="--0:#C792EA;--1:#8844AE">type</span><span style="--0:#D6DEEB;--1:#403F53"> Input </span><span style="--0:#C792EA;--1:#8844AE">=</span><span style="--0:#D6DEEB;--1:#403F53"> { url</span><span style="--0:#7FDBCA;--1:#096E72">:</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#C5E478;--1:#3B61B0">string</span><span style="--0:#D6DEEB;--1:#403F53"> };</span></div></div><div class="ec-line"><div class="code"> 412</div></div><div class="ec-line"><div class="code"><span style="--0:#7FDBCA;--1:#096E72">new</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#82AAFF;--1:#3B61B0">Flow</span><span style="--0:#D6DEEB;--1:#403F53"><</span><span style="--0:#FFCB8B;--1:#111111">Input</span><span style="--0:#D6DEEB;--1:#403F53">>({ slug: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">process_article</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53"> })</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#C792EA;--1:#8844AE">
412.</span><span style="--0:#82AAFF;--1:#3B61B0">step</span><span style="--0:#D6DEEB;--1:#403F53">(</span></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#D6DEEB;--1:#403F53"> </span></span><span style="--0:#D6DEEB;--1:#403F53">{ slug: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">fetchArticle</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53"> },</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#C792EA;--1:#8844AE">async</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#D9F5DD;--1:#111111">(</span><span style="--0:#D7DBE0;--1:#403F53">flowInput</span><span style="--0:#D9F5DD;--1:#111111">)</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#C792EA;--1:#8844AE">=></span><span style="--0:#D6DEEB;--1:#403F53"> {</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#C792EA;--1:#8844AE">const </span><span style="--0:#82AAFF;--1:#3B61B0">response</span><span style="--0:#C792EA;--1:#8844AE"> = await </span><span style="--0:#82AAFF;--1:#3B61B0">fetch</span><span style="--0:#D6DEEB;--1:#403F53">(</span><mark><span style="--0:#D6DEEB;--1:#403F53">flowInput</span><span style="--0:#d0a4ed;--1:#753a96">.</span><span style="--0:#7FDBCA;--1:#085f62">url</span></mark><span style="--0:#D6DEEB;--1:#403F53">);</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#C792EA;--1:#8844AE">return</span><span style="--0:#D6DEEB;--1:#403F53"> response</span><span style="--0:#C792EA;--1:#8844AE">.</span><span style="--0:#82AAFF;--1:#3B61B0">text</span><span style="--0:#D6DEEB;--1:#403F53">();</span></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#D6DEEB;--1:#403F53"> </span></span><span style="--0:#D6DEEB;--1:#403F53">}</span></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#D6DEEB;--1:#403F53"> </span></span><span style="--0:#D6DEEB;--1:#403F53">)</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#C792EA;--1:#8844AE">.</span><span style="--0:#82AAFF;--1:#3B61B0">step</span><span style="--0:#D6DEEB;--1:#403F53">(</span></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#D6DEEB;--1:#403F53"> </span></span><span style="--0:#D6DEEB;--1:#403F53">{ slug: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">summarize</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">, </span><mark><span style="--0:#D6DEEB;--1:#403F53">dependsOn: [</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#804241">fetchArticle</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">]</span></mark><span style="--0:#D6DEEB;--1:#403F53"> },</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#C792EA;--1:#8844AE">async</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#D9F5DD;--1:#111111">(</span><span style="--0:#D7DBE0;--1:#403F53">deps</span><span style="--0:#D9F5DD;--1:#111111">)</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#C792EA;--1:#8844AE">=></span><span style="--0:#D6DEEB;--1:#403F53"> {</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#C792EA;--1:#8844AE">return</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#C792EA;--1:#8844AE">await</span><span style="--0:#D6DEEB;--1:#403F53"> openai</span><span style="--0:#C792EA;--1:#8844AE">.</span><span style="--0:#82AAFF;--1:#3B61B0">summarize</span><span style="--0:#D6DEEB;--1:#403F53">(</span><mark><span style="--0:#D6DEEB;--1:#403F53">deps</span><span style="--0:#d0a4ed;--1:#753a96">.</span><span style="--0:#7FDBCA;--1:#085f62">fetchArticle</span></mark><span style="--0:#D6DEEB;--1:#403F53">);</span></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#D6DEEB;--1:#403F53"> </span></span><span style="--0:#D6DEEB;--1:#403F53">}</span></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#D6DEEB;--1:#403F53"> </span></span><span style="--0:#D6DEEB;--1:#403F53">)</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#C792EA;--1:#8844AE">
412.</span><span style="--0:#82AAFF;--1:#3B61B0">step</span><span style="--0:#D6DEEB;--1:#403F53">(</span></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#D6DEEB;--1:#403F53"> </span></span><span style="--0:#D6DEEB;--1:#403F53">{ slug: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">extractKeywords</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">, </span><mark><span style="--0:#D6DEEB;--1:#403F53">dependsOn: [</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#804241">fetchArticle</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">]</span></mark><span style="--0:#D6DEEB;--1:#403F53"> },</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#C792EA;--1:#8844AE">async</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#D9F5DD;--1:#111111">(</span><span style="--0:#D7DBE0;--1:#403F53">deps</span><span style="--0:#D9F5DD;--1:#111111">)</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#C792EA;--1:#8844AE">=></span><span style="--0:#D6DEEB;--1:#403F53"> {</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#C792EA;--1:#8844AE">return</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#C792EA;--1:#8844AE">await</span><span style="--0:#D6DEEB;--1:#403F53"> openai</span><span style="--0:#C792EA;--1:#8844AE">.</span><span style="--0:#82AAFF;--1:#3B61B0">extractKeywords</span><span style="--0:#D6DEEB;--1:#403F53">(</span><mark><span style="--0:#D6DEEB;--1:#403F53">deps</span><span style="--0:#d0a4ed;--1:#753a96">.</span><span style="--0:#7FDBCA;--1:#085f62">fetchArticle</span></mark><span style="--0:#D6DEEB;--1:#403F53">);</span></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#D6DEEB;--1:#403F53"> </span></span><span style="--0:#D6DEEB;--1:#403F53">}</span></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#D6DEEB;--1:#403F53"> </span></span><span style="--0:#D6DEEB;--1:#403F53">)</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#C792EA;--1:#8844AE">.</span><span style="--0:#82AAFF;--1:#3B61B0">step</span><span style="--0:#D6DEEB;--1:#403F53">(</span></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#D6DEEB;--1:#403F53"> </span></span><span style="--0:#D6DEEB;--1:#403F53">{ slug: </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">publish</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">, </span><mark><span style="--0:#D6DEEB;--1:#403F53">dependsOn: [</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#804241">summarize</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">, </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#804241">extractKeywords</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">]</span></mark><span style="--0:#D6DEEB;--1:#403F53"> },</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#C792EA;--1:#8844AE">async</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#D9F5DD;--1:#111111">(</span><span style="--0:#D7DBE0;--1:#403F53">deps</span><span style="--0:#D9F5DD;--1:#111111">)</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#C792EA;--1:#8844AE">=></span><span style="--0:#D6DEEB;--1:#403F53"> {</span></div></div><div class="ec-line"><div class="code"><span class="indent"> </span><span style="--0:#C792EA;--1:#8844AE">await</span><span style="--0:#D6DEEB;--1:#403F53"> db</span><span style="--0:#C792EA;--1:#8844AE">.</span><span style="--0:#82AAFF;--1:#3B61B0">insert</span><span style="--0:#D6DEEB;--1:#403F53">
412({</span></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#D6DEEB;--1:#403F53"> </span></span><span style="--0:#D6DEEB;--1:#403F53">summary: </span><mark><span style="--0:#D6DEEB;--1:#403F53">deps</span><span style="--0:#d0a4ed;--1:#753a96">.</span><span style="--0:#7FDBCA;--1:#085f62">summarize</span></mark><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#D6DEEB;--1:#403F53"> </span></span><span style="--0:#D6DEEB;--1:#403F53">keywords: </span><mark><span style="--0:#D6DEEB;--1:#403F53">deps</span><span style="--0:#d0a4ed;--1:#753a96">.</span><span style="--0:#7FDBCA;--1:#085f62">extractKeywords</span></mark></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#D6DEEB;--1:#403F53"> </span></span><span style="--0:#D6DEEB;--1:#403F53">});</span></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#D6DEEB;--1:#403F53"> </span></span><span style="--0:#D6DEEB;--1:#403F53">}</span></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#D6DEEB;--1:#403F53"> </span></span><span style="--0:#D6DEEB;--1:#403F53">);</span></div></div></code></pre><div class="copy"><button title="Copy to clipboard" data-copied="Copied!" data-code="type Input = { url: string };��new Flow<Input>({ slug: "process_article" })� .step(� { slug: "fetchArticle" },� async (flowInput) => {� const response = await fetch(flowInput.url);� return response.text();� }� )� .step(� { slug: "summarize", dependsOn: ["fetchArticle"] },� async (deps) => {� return await openai.summarize(deps.fetchArticle);� }� )� .step(� { slug: "extractKeywords", dependsOn: ["fetchArticle"] },� async (deps) => {� return await openai.extractKeywords(deps.fetchArticle);� }� )� .step(� { slug: "publish", dependsOn: ["summarize", "extractKeywords"] },� async (deps) => {� await db.insert({� summary: deps.summarize,� keywords: deps.extractKeywords� });� }� );"><div></div></button></div></figure></div></details> 413<div class="sl-heading-wrapper level-h2"><h2 id="deploy-as-edge-function">Deploy as Edge Function</h2><a class="sl-anchor-link" href="#deploy-as-edge-function"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24"><path fill="currentcolor" d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z"></path></svg></span><span class="sr-only">Section titled âDeploy as Edge Functionâ</span></a></div> 414<p>No <strong>Deno.serve</strong> boilerplate - three lines sets up a <a href="/reference/queue-worker/how-it-works/">persistent</a> worker:</p> 415<div class="expressive-code"><figure class="frame not-content"><figcaption class="header"></figcaption><pre data-language="typescript"><code><div class="ec-line"><div class="code"><span style="--0:#C792EA;--1:#8844AE">import</span><span style="--0:#D6DEEB;--1:#403F53"> { EdgeWorker } </span><span style="--0:#C792EA;--1:#8844AE">from</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#ECC48D;--1:#984E4D">jsr:@pgflow/edge-worker</span><span style="--0:#D9F5DD;--1:#111111">"</span><span style="--0:#D6DEEB;--1:#403F53">;</span></div></div><div class="ec-line"><div class="code"><span style="--0:#C792EA;--1:#8844AE">import</span><span style="--0:#D6DEEB;--1:#403F53"> ProcessArticle </span><span style="--0:#C792EA;--1:#8844AE">from</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#D9F5DD;--1:#111111">'</span><span style="--0:#ECC48D;--1:#984E4D">./process_article.ts</span><span style="--0:#D9F5DD;--1:#111111">'</span><span style="--0:#D6DEEB;--1:#403F53">;</span></div></div><div class="ec-line"><div class="code"> 416</div></div><div class="ec-line"><div class="code"><span style="--0:#D6DEEB;--1:#403F53">EdgeWorker</span><span style="--0:#C792EA;--1:#8844AE">
416.</span><span style="--0:#82AAFF;--1:#3B61B0">start</span><span style="--0:#D6DEEB;--1:#403F53">(ProcessArticle);</span></div></div></code></pre><div class="copy"><button title="Copy to clipboard" data-copied="Copied!" data-code="import { EdgeWorker } from "jsr:@pgflow/edge-worker";�import ProcessArticle from './process_article.ts';��EdgeWorker.start(ProcessArticle);"><div></div></button></div></figure></div> 417<aside aria-label="Continuous Workers" class="starlight-aside starlight-aside--note"> <p class="starlight-aside__title" aria-hidden="true"> <svg aria-hidden="true" class="starlight-aside__icon astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M12 11a1 1 0 0 0-1 1v4a1 1 0 0 0 2 0v-4a1 1 0 0 0-1-1Zm.38-3.92a1 1 0 0 0-.76 0 1 1 0 0 0-.33.21 1.15 1.15 0 0 0-.21.33 1 1 0 0 0 .21 1.09c.097.088.209.16.33.21A1 1 0 0 0 13 8a1.05 1.05 0 0 0-.29-.71 1 1 0 0 0-.33-.21ZM12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20Zm0 18a8 8 0 1 1 0-16.001A8 8 0 0 1 12 20Z"/></svg>Continuous Workers </p> <div class="starlight-aside__content"> <p>pgflow workers use Supabase Background Tasks and add automatic respawning, continuous polling, and heartbeats for ease of use, continuity, observability, and <100ms task startup. <a href="/reference/queue-worker/how-it-works/">How it works â</a></p> </div> </aside> 418<div class="sl-heading-wrapper level-h2"><h2 id="start-your-flow">Start Your Flow</h2><a class="sl-anchor-link" href="#start-your-flow"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24"><path fill="currentcolor" d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z"></path></svg></span><span class="sr-only">Section titled âStart Your Flowâ</span></a></div> 419<p>Trigger a run from SQL:</p> 420<div class="expressive-code"><figure class="frame not-content"><figcaption class="header"></figcaption><pre data-language="sql"><code><div class="ec-line"><div class="code"><span style="--0:#C792EA;--1:#8844AE">SELECT</span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#82AAFF;--1:#3B61B0">pgflow</span><span style="--0:#D6DEEB;--1:#403F53">.</span><span style="--0:#82AAFF;--1:#3B61B0">start_flow</span><span style="--0:#D6DEEB;--1:#403F53">(</span></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#D6DEEB;--1:#403F53"> </span></span><span style="--0:#D6DEEB;--1:#403F53">flow_slug </span><span style="--0:#C792EA;--1:#8844AE">=></span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#D9F5DD;--1:#111111">'</span><span style="--0:#ECC48D;--1:#984E4D">process_article</span><span style="--0:#D9F5DD;--1:#111111">'</span><span style="--0:#D6DEEB;--1:#403F53">,</span></div></div><div class="ec-line"><div class="code"><span class="indent"><span style="--0:#D6DEEB;--1:#403F53"> </span></span><span style="--0:#D6DEEB;--1:#403F53">input </span><span style="--0:#C792EA;--1:#8844AE">=></span><span style="--0:#D6DEEB;--1:#403F53"> </span><span style="--0:#D9F5DD;--1:#111111">'</span><span style="--0:#ECC48D;--1:#984E4D">{"url": "https://example.com"}</span><span style="--0:#D9F5DD;--1:#111111">'</span><span style="--0:#D6DEEB;--1:#403F53">::jsonb</span></div></div><div class="ec-line"><div class="code"><span style="--0:#D6DEEB;--1:#403F53">);</span></div></div></code></pre><div class="copy"><button title="Copy to clipboard" data-copied="Copied!" data-code="SELECT pgflow.start_flow(� flow_slug => 'process_article',� input => '{"url": "https://example.com"}'::jsonb�);"><div></div></button></div></figure></div> 421<p>Since itâs a SQL function, call it anywhere: schedule with <code dir="auto">pg_cron</code>, use in db triggers, within transactions, from your app via Supabase RPC, or use the pgflow client for realtime updates.</p> 422<hr> 423<p>Thatâs it - dependencies determine execution order, pgflow handles parallelism and retries, all state lives in Postgres.</p> 424<div class="sl-heading-wrapper level-h2"><h2 id="learn-more">Learn More</h2><a class="sl-anchor-link" href="#learn-more"><span aria-hidden="true" class="sl-anchor-icon">
424<svg width="16" height="16" viewBox="0 0 24 24"><path fill="currentcolor" d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z"></path></svg></span><span class="sr-only">Section titled âLearn Moreâ</span></a></div> 425<div class="card-grid astro-y4xfamor"><div class="sl-link-card astro-bhcct7ef"> <span class="sl-flex stack astro-bhcct7ef"> <a href="/get-started/installation/" class="astro-bhcct7ef"> <span class="title astro-bhcct7ef">Install pgflow</span> </a> <span class="description astro-bhcct7ef">Set up pgflow in your Supabase project with one command</span> </span> <svg aria-hidden="true" class="icon rtl:flip astro-bhcct7ef astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.333em;"><path d="M17.92 11.62a1.001 1.001 0 0 0-.21-.33l-5-5a1.003 1.003 0 1 0-1.42 1.42l3.3 3.29H7a1 1 0 0 0 0 2h7.59l-3.3 3.29a1.002 1.002 0 0 0 .325 1.639 1 1 0 0 0 1.095-.219l5-5a1 1 0 0 0 .21-.33 1 1 0 0 0 0-.76Z"/></svg> </div> <div class="sl-link-card astro-bhcct7ef"> <span class="sl-flex stack astro-bhcct7ef"> <a href="/get-started/flows/create-flow/" class="astro-bhcct7ef"> <span class="title astro-bhcct7ef">Create your first flow</span> </a> <span class="description astro-bhcct7ef">Build a simple workflow to see how steps connect</span> </span> <svg aria-hidden="true" class="icon rtl:flip astro-bhcct7ef astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.333em;"><path d="M17.92 11.62a1.001 1.001 0 0 0-.21-.33l-5-5a1.003 1.003 0 1 0-1.42 1.42l3.3 3.29H7a1 1 0 0 0 0 2h7.59l-3.3 3.29a1.002 1.002 0 0 0 .325 1.639 1 1 0 0 0 1.095-.219l5-5a1 1 0 0 0 .21-.33 1 1 0 0 0 0-.76Z"/></svg> </div> <div class="sl-link-card astro-bhcct7ef"> <span class="sl-flex stack astro-bhcct7ef"> <a href="/deploy/monitor-execution/" class="astro-bhcct7ef"> <span class="title astro-bhcct7ef">Monitor Execution</span> </a> <span class="description astro-bhcct7ef">Query step states, view execution timeline, troubleshoot failures</span> </span> <svg aria-hidden="true" class="icon rtl:flip astro-bhcct7ef astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.333em;"><path d="M17.92 11.62a1.001 1.001 0 0 0-.21-.33l-5-5a1.003 1.003 0 1 0-1.42 1.42l3.3 3.29H7a1 1 0 0 0 0 2h7.59l-3.3 3.29a1.002 1.002 0 0 0 .325 1.639 1 1 0 0 0 1.095-.219l5-5a1 1 0 0 0 .21-.33 1 1 0 0 0 0-.76Z"/></svg> </div> <div class="sl-link-card astro-bhcct7ef"> <span class="sl-flex stack astro-bhcct7ef"> <a href="/concepts/failures-and-termination/" class="astro-bhcct7ef"> <span class="title astro-bhcct7ef">Failures and termination</span> </a> <span class="description astro-bhcct7ef">Understand retries, failed runs, cancelled work, and stalled recovery</span> </span> <svg aria-hidden="true" class="icon rtl:flip astro-bhcct7ef astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.333em;"><path d="M17.92 11.62a1.001 1.001 0 0 0-.21-.33l-5-5a1.003 1.003 0 1 0-1.42 1.42l3.3 3.29H7a1 1 0 0 0 0 2h7.59l-3.3 3.29a1.002 1.002 0 0 0 .325 1.639 1 1 0 0 0 1.095-.219l5-5a1 1 0 0 0 .21-.33 1 1 0 0 0 0-.76Z"/></svg> </div> <div class="sl-link-card astro-bhcct7ef"> <span class="sl-flex stack astro-bhcct7ef"> <a href="/concepts/three-layer-architecture/" class="astro-bhcct7ef"> <span class="title astro-bhcct7ef">Three-layer architecture</span> </a> <span class="description astro-bhcct7ef">Deep dive into three-layer separation and design philosophy</span> </span> <svg aria-hidden="true" class="icon rtl:flip astro-bhcct7ef astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.333em;"><path d="M17.92 11.62a1.001 1.001 0 0 0-.21-.33l-5-5a1.003 1.003 0 1 0-1.42 1.42l3.3 3.29H7a1 1 0 0 0 0 2h7.59l-3.3 3.29a1.002 1.002 0 0 0 .325 1.639 1 1 0 0 0 1.095-.219l5-5a1 1 0 0 0 .21-.33 1 1 0 0 0 0-.76Z"/></svg> </div> </div> 426<h2>Join the Community</h2> <article class="card sl-flex astro-5y3mj7uu"> <p class="title sl-flex astro-5y3mj7uu"> <svg aria-hidden="true" class="icon astro-5y3mj7uu astro-i27iqf3l" width="16" height="16" viewB
426ox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.333em;"><path d="M20.32 4.37a19.8 19.8 0 0 0-4.93-1.51 13.78 13.78 0 0 0-.64 1.28 18.27 18.27 0 0 0-5.5 0 12.64 12.64 0 0 0-.64-1.28h-.05A19.74 19.74 0 0 0 3.64 4.4 20.26 20.26 0 0 0 .11 18.09l.02.02a19.9 19.9 0 0 0 6.04 3.03l.04-.02a14.24 14.24 0 0 0 1.23-2.03.08.08 0 0 0-.05-.07 13.1 13.1 0 0 1-1.9-.92.08.08 0 0 1 .02-.1 10.2 10.2 0 0 0 .41-.31h.04a14.2 14.2 0 0 0 12.1 0l.04.01a9.63 9.63 0 0 0 .4.32.08.08 0 0 1-.03.1 12.29 12.29 0 0 1-1.9.91.08.08 0 0 0-.02.1 15.97 15.97 0 0 0 1.27 2.01h.04a19.84 19.84 0 0 0 6.03-3.05v-.03a20.12 20.12 0 0 0-3.57-13.69ZM8.02 15.33c-1.18 0-2.16-1.08-2.16-2.42 0-1.33.96-2.42 2.16-2.42 1.21 0 2.18 1.1 2.16 2.42 0 1.34-.96 2.42-2.16 2.42Zm7.97 0c-1.18 0-2.15-1.08-2.15-2.42 0-1.33.95-2.42 2.15-2.42 1.22 0 2.18 1.1 2.16 2.42 0 1.34-.94 2.42-2.16 2.42Z"/></svg> <span class="astro-5y3mj7uu">Connect on Discord</span> </p> <div class="body astro-5y3mj7uu"> 427Have questions or need help? pgflow is just getting started - join us on Discord to ask questions, share feedback, or discuss partnership opportunities. 428<h5><strong><a href="https://pgflow.dev/discord/" class="plausible-event-name=discord:join-click">Join Discord â</a></strong></h5> </div> </article> </div> <footer class="sl-flex astro-7hkty3uh"> <div class="meta sl-flex astro-7hkty3uh"> <a href="https://github.com/pgflow-dev/pgflow/edit/main/pkgs/website/src/content/docs/concepts/how-pgflow-works.mdx" class="sl-flex print:hidden astro-ajbslzzy"><svg aria-hidden="true" class="astro-ajbslzzy astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.2em;"><path d="M22 7.24a1 1 0 0 0-.29-.71l-4.24-4.24a1 1 0 0 0-1.1-.22 1 1 0 0 0-.32.22l-2.83 2.83L2.29 16.05a1 1 0 0 0-.29.71V21a1 1 0 0 0 1 1h4.24a1 1 0 0 0 .76-.29l10.87-10.93L21.71 8c.1-.1.17-.2.22-.33a1 1 0 0 0 0-.24v-.14l.07-.05ZM6.83 20H4v-2.83l9.93-9.93 2.83 2.83L6.83 20ZM18.17 8.66l-2.83-2.83 1.42-1.41 2.82 2.82-1.41 1.42Z"/></svg>Edit page</a> </div> <div class="pagination-links print:hidden astro-sbnakd2b" dir="ltr"> <a href="/concepts/" rel="prev" class="astro-sbnakd2b"> <svg aria-hidden="true" class="astro-sbnakd2b astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.5rem;"><path d="M17 11H9.41l3.3-3.29a1.004 1.004 0 1 0-1.42-1.42l-5 5a1 1 0 0 0-.21.33 1 1 0 0 0 0 .76 1 1 0 0 0 .21.33l5 5a1.002 1.002 0 0 0 1.639-.325 1 1 0 0 0-.219-1.095L9.41 13H17a1 1 0 0 0 0-2Z"/></svg> <span class="astro-sbnakd2b"> Previous <br class="astro-sbnakd2b"> <span class="link-title astro-sbnakd2b">Overview</span> </span> </a> <a href="/concepts/three-layer-architecture/" rel="next" class="astro-sbnakd2b"> <svg aria-hidden="true" class="astro-sbnakd2b astro-i27iqf3l" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.5rem;"><path d="M17.92 11.62a1.001 1.001 0 0 0-.21-.33l-5-5a1.003 1.003 0 1 0-1.42 1.42l3.3 3.29H7a1 1 0 0 0 0 2h7.59l-3.3 3.29a1.002 1.002 0 0 0 .325 1.639 1 1 0 0 0 1.095-.219l5-5a1 1 0 0 0 .21-.33 1 1 0 0 0 0-.76Z"/></svg> <span class="astro-sbnakd2b"> Next <br class="astro-sbnakd2b"> <span class="link-title astro-sbnakd2b">Three-layer architecture</span> </span> </a> </div> </footer> </div> </div> </main> </div> </div> </div> </div> <a href="/author/" class="hire-sticker astro-4toy2ex6"> 429Chat with Author 430</a>
430<script type="module" src="https://static.cloudflareinsights.com/beacon.min.js/v31edd6df95cf4e85bb4c19e7a9bdbcba1788362987495" integrity="sha512-iIg7k2xntmwu6/uSb5tpc/hySgZc4eoL31yB29W6tJFo2akwjPWcEqnCEdJvGexCL0KEQwVYv5BlowfhVz26hg==" data-cf-beacon='{"version":"2024.11.0","token":"6a9f65c63e1249e3868e0df7798f3b54","r":1,"spa":2}' crossorigin="anonymous"></script>
430 431</body></html>
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.