PageSourceSearch

https://www.pgflow.dev/concepts/how-pgflow-works/

html pgflow.dev collected 2026-10-03 22:55:44 UTC 100,704 bytes, 431 lines download raw bytes

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="{&#34;placeholder&#34;:&#34;Search&#34;}"> <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">&#x3C;</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: &#x22;process_article&#x22; })�  .step({ slug: &#x22;fetchArticle&#x22; }, fn)�  .step({ slug: &#x22;summarize&#x22;, dependsOn: [&#x22;fetchArticle&#x22;] }, fn)�  .step({ slug: &#x22;extractKeywords&#x22;, dependsOn: [&#x22;fetchArticle&#x22;] }, fn)�  .step({ slug: &#x22;publish&#x22;, dependsOn: [&#x22;summarize&#x22;, &#x22;extractKeywords&#x22;] }, 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.&#x3C;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">&#x3C;</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: &#x22;process_article&#x22; })�  .step(�    { slug: &#x22;fetchArticle&#x22; },�    async (flowInput) => {�      const response = await fetch(flowInput.url);�      return response.text();�    }�  )�  .step(�    { slug: &#x22;summarize&#x22;, dependsOn: [&#x22;fetchArticle&#x22;] },�    async (deps) => {�      return await openai.summarize(deps.fetchArticle);�    }�  )�  .step(�    { slug: &#x22;extractKeywords&#x22;, dependsOn: [&#x22;fetchArticle&#x22;] },�    async (deps) => {�      return await openai.extractKeywords(deps.fetchArticle);�    }�  )�  .step(�    { slug: &#x22;publish&#x22;, dependsOn: [&#x22;summarize&#x22;, &#x22;extractKeywords&#x22;] },�    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 &#x22;jsr:@pgflow/edge-worker&#x22;;�import ProcessArticle from &#x27;./process_article.ts&#x27;;��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 &#x3C;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 => &#x27;process_article&#x27;,�  input => &#x27;{&#x22;url&#x22;: &#x22;https://example.com&#x22;}&#x27;::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.