[{"data":1,"prerenderedAt":2419},["ShallowReactive",2],{"navigation":3,"\u002Fdocs\u002Fbuilding":314,"\u002Fdocs\u002Fbuilding-surround":2414},[4,38,86,149,176,219,257,273],{"title":5,"path":6,"stem":7,"children":8,"icon":37},"Getting Started","\u002Fdocs\u002Fgetting-started","1.docs\u002F1.getting-started\u002F1.index",[9,12,17,22,27,32],{"title":10,"path":6,"stem":7,"icon":11},"Getting started","i-lucide-flag",{"title":13,"path":14,"stem":15,"icon":16},"Modules overview","\u002Fdocs\u002Fgetting-started\u002Fmodules-overview","1.docs\u002F1.getting-started\u002F2.modules-overview","i-lucide-boxes",{"title":18,"path":19,"stem":20,"icon":21},"Installation","\u002Fdocs\u002Fgetting-started\u002Finstallation","1.docs\u002F1.getting-started\u002F3.installation","i-lucide-download",{"title":23,"path":24,"stem":25,"icon":26},"License configuration","\u002Fdocs\u002Fgetting-started\u002Flicense-configuration","1.docs\u002F1.getting-started\u002F4.license-configuration","i-lucide-key-round",{"title":28,"path":29,"stem":30,"icon":31},"Your first app","\u002Fdocs\u002Fgetting-started\u002Ffirst-app","1.docs\u002F1.getting-started\u002F5.first-app","i-lucide-square-play",{"title":33,"path":34,"stem":35,"icon":36},"Project setup","\u002Fdocs\u002Fgetting-started\u002Fproject-setup","1.docs\u002F1.getting-started\u002F6.project-setup","i-lucide-package",false,{"title":39,"path":40,"stem":41,"children":42,"icon":45},"Core Concepts","\u002Fdocs\u002Fconcepts","1.docs\u002F2.concepts\u002F1.index",[43,46,51,56,61,66,71,76,81],{"title":44,"path":40,"stem":41,"icon":45},"Core concepts","i-lucide-book-open",{"title":47,"path":48,"stem":49,"icon":50},"Architecture","\u002Fdocs\u002Fconcepts\u002Farchitecture","1.docs\u002F2.concepts\u002F2.architecture","i-lucide-layers",{"title":52,"path":53,"stem":54,"icon":55},"Exactly-once semantics","\u002Fdocs\u002Fconcepts\u002Fexactly-once","1.docs\u002F2.concepts\u002F3.exactly-once","i-lucide-shield-check",{"title":57,"path":58,"stem":59,"icon":60},"Lanes and parallelism","\u002Fdocs\u002Fconcepts\u002Flanes-and-parallelism","1.docs\u002F2.concepts\u002F4.lanes-and-parallelism","i-lucide-split",{"title":62,"path":63,"stem":64,"icon":65},"State and thread-safety","\u002Fdocs\u002Fconcepts\u002Fstate-and-thread-safety","1.docs\u002F2.concepts\u002F5.state-and-thread-safety","i-lucide-lock",{"title":67,"path":68,"stem":69,"icon":70},"Event time and watermarks","\u002Fdocs\u002Fconcepts\u002Fevent-time-and-watermarks","1.docs\u002F2.concepts\u002F6.event-time-and-watermarks","i-lucide-clock",{"title":72,"path":73,"stem":74,"icon":75},"The configuration model","\u002Fdocs\u002Fconcepts\u002Fconfiguration-model","1.docs\u002F2.concepts\u002F7.configuration-model","i-lucide-sliders-horizontal",{"title":77,"path":78,"stem":79,"icon":80},"The error-handling model","\u002Fdocs\u002Fconcepts\u002Ferror-handling-model","1.docs\u002F2.concepts\u002F8.error-handling-model","i-lucide-triangle-alert",{"title":82,"path":83,"stem":84,"icon":85},"How StoatFlow differs from Kafka Streams","\u002Fdocs\u002Fconcepts\u002Fhow-stoatflow-differs-from-ks","1.docs\u002F2.concepts\u002F9.how-stoatflow-differs-from-ks","i-lucide-arrow-left-right",{"title":87,"path":88,"stem":89,"children":90,"icon":93},"Building Topologies","\u002Fdocs\u002Fbuilding","1.docs\u002F3.building\u002F1.index",[91,94,99,104,109,114,119,124,129,134,139,144],{"title":92,"path":88,"stem":89,"icon":93},"Building topologies","i-lucide-blocks",{"title":95,"path":96,"stem":97,"icon":98},"Error handling and DLQ","\u002Fdocs\u002Fbuilding\u002Ferror-handling-dlq","1.docs\u002F3.building\u002F10.error-handling-dlq","i-lucide-circle-x",{"title":100,"path":101,"stem":102,"icon":103},"State stores","\u002Fdocs\u002Fbuilding\u002Fstate-stores","1.docs\u002F3.building\u002F11.state-stores","i-lucide-database",{"title":105,"path":106,"stem":107,"icon":108},"Testing topologies","\u002Fdocs\u002Fbuilding\u002Ftesting","1.docs\u002F3.building\u002F12.testing","i-lucide-flask-conical",{"title":110,"path":111,"stem":112,"icon":113},"Sources and sinks","\u002Fdocs\u002Fbuilding\u002Fstreams-builder","1.docs\u002F3.building\u002F2.streams-builder","i-lucide-import",{"title":115,"path":116,"stem":117,"icon":118},"KStream and KTable operations","\u002Fdocs\u002Fbuilding\u002Fkstream-ktable","1.docs\u002F3.building\u002F3.kstream-ktable","i-lucide-waypoints",{"title":120,"path":121,"stem":122,"icon":123},"Aggregations","\u002Fdocs\u002Fbuilding\u002Faggregations","1.docs\u002F3.building\u002F4.aggregations","i-lucide-sigma",{"title":125,"path":126,"stem":127,"icon":128},"Windowing","\u002Fdocs\u002Fbuilding\u002Fwindowing","1.docs\u002F3.building\u002F5.windowing","i-lucide-calendar-clock",{"title":130,"path":131,"stem":132,"icon":133},"Joins","\u002Fdocs\u002Fbuilding\u002Fjoins","1.docs\u002F3.building\u002F6.joins","i-lucide-git-merge",{"title":135,"path":136,"stem":137,"icon":138},"The Processor API","\u002Fdocs\u002Fbuilding\u002Fprocessor-api","1.docs\u002F3.building\u002F7.processor-api","i-lucide-cpu",{"title":140,"path":141,"stem":142,"icon":143},"Scheduled sources","\u002Fdocs\u002Fbuilding\u002Fscheduled-sources","1.docs\u002F3.building\u002F8.scheduled-sources","i-lucide-timer",{"title":145,"path":146,"stem":147,"icon":148},"Serdes and Avro","\u002Fdocs\u002Fbuilding\u002Fserdes","1.docs\u002F3.building\u002F9.serdes","i-lucide-binary",{"title":150,"path":151,"stem":152,"children":153,"icon":75},"Configuration","\u002Fdocs\u002Fconfiguration","1.docs\u002F4.configuration\u002F1.index",[154,156,161,166,171],{"title":155,"path":151,"stem":152,"icon":75},"How configuration works",{"title":157,"path":158,"stem":159,"icon":160},"Engine configuration (:core)","\u002Fdocs\u002Fconfiguration\u002Fcore-config","1.docs\u002F4.configuration\u002F2.core-config","i-lucide-settings-2",{"title":162,"path":163,"stem":164,"icon":165},"Runtime configuration (:runtime)","\u002Fdocs\u002Fconfiguration\u002Fruntime-config","1.docs\u002F4.configuration\u002F3.runtime-config","i-lucide-server-cog",{"title":167,"path":168,"stem":169,"icon":170},"Defaults, adaptivity, and presets","\u002Fdocs\u002Fconfiguration\u002Fdefaults-and-presets","1.docs\u002F4.configuration\u002F4.defaults-and-presets","i-lucide-gauge",{"title":172,"path":173,"stem":174,"icon":175},"Kafka client configuration","\u002Fdocs\u002Fconfiguration\u002Fkafka-client-config","1.docs\u002F4.configuration\u002F5.kafka-client-config","i-lucide-plug",{"title":177,"path":178,"stem":179,"children":180,"icon":183},"Running in Production","\u002Fdocs\u002Fruntime","1.docs\u002F5.runtime\u002F1.index",[181,184,189,194,199,204,209,214],{"title":182,"path":178,"stem":179,"icon":183},"The runtime","i-lucide-server",{"title":185,"path":186,"stem":187,"icon":188},"The REST API","\u002Fdocs\u002Fruntime\u002Frest-api","1.docs\u002F5.runtime\u002F2.rest-api","i-lucide-globe",{"title":190,"path":191,"stem":192,"icon":193},"Health checks","\u002Fdocs\u002Fruntime\u002Fhealth-checks","1.docs\u002F5.runtime\u002F3.health-checks","i-lucide-heart-pulse",{"title":195,"path":196,"stem":197,"icon":198},"Metrics","\u002Fdocs\u002Fruntime\u002Fmetrics","1.docs\u002F5.runtime\u002F4.metrics","i-lucide-activity",{"title":200,"path":201,"stem":202,"icon":203},"Pause and resume","\u002Fdocs\u002Fruntime\u002Fpause-unpause","1.docs\u002F5.runtime\u002F5.pause-unpause","i-lucide-pause",{"title":205,"path":206,"stem":207,"icon":208},"Plugins and lifecycle hooks","\u002Fdocs\u002Fruntime\u002Fplugins","1.docs\u002F5.runtime\u002F6.plugins","i-lucide-puzzle",{"title":210,"path":211,"stem":212,"icon":213},"Docker images","\u002Fdocs\u002Fruntime\u002Fdocker","1.docs\u002F5.runtime\u002F7.docker","i-lucide-container",{"title":215,"path":216,"stem":217,"icon":218},"GraalVM native image","\u002Fdocs\u002Fruntime\u002Fnative-image","1.docs\u002F5.runtime\u002F8.native-image","i-lucide-zap",{"title":220,"path":221,"stem":222,"children":223,"icon":226},"Deploying & Operating","\u002Fdocs\u002Foperating","1.docs\u002F6.operating\u002F1.index",[224,227,232,237,242,247,252],{"title":225,"path":221,"stem":222,"icon":226},"Deploying and operating","i-lucide-life-buoy",{"title":228,"path":229,"stem":230,"icon":231},"Running on Kubernetes","\u002Fdocs\u002Foperating\u002Fkubernetes","1.docs\u002F6.operating\u002F2.kubernetes","i-lucide-ship",{"title":233,"path":234,"stem":235,"icon":236},"High availability","\u002Fdocs\u002Foperating\u002Fhigh-availability","1.docs\u002F6.operating\u002F3.high-availability","i-lucide-copy",{"title":238,"path":239,"stem":240,"icon":241},"Liveness and readiness probes","\u002Fdocs\u002Foperating\u002Fprobes","1.docs\u002F6.operating\u002F4.probes","i-lucide-stethoscope",{"title":243,"path":244,"stem":245,"icon":246},"Observability","\u002Fdocs\u002Foperating\u002Fobservability","1.docs\u002F6.operating\u002F5.observability","i-lucide-telescope",{"title":248,"path":249,"stem":250,"icon":251},"Tuning under load","\u002Fdocs\u002Foperating\u002Ftuning","1.docs\u002F6.operating\u002F6.tuning","i-lucide-sliders",{"title":253,"path":254,"stem":255,"icon":256},"Production checklist","\u002Fdocs\u002Foperating\u002Fproduction-checklist","1.docs\u002F6.operating\u002F7.production-checklist","i-lucide-clipboard-check",{"title":258,"path":259,"stem":260,"children":261,"icon":85},"Migrating from Kafka Streams","\u002Fdocs\u002Fmigration","1.docs\u002F7.migration\u002F1.index",[262,263,268],{"title":258,"path":259,"stem":260,"icon":85},{"title":264,"path":265,"stem":266,"icon":267},"Migration without carrying state","\u002Fdocs\u002Fmigration\u002Fwithout-data-migration","1.docs\u002F7.migration\u002F2.without-data-migration","i-lucide-sparkles",{"title":269,"path":270,"stem":271,"icon":272},"Migration carrying state","\u002Fdocs\u002Fmigration\u002Fwith-data-migration","1.docs\u002F7.migration\u002F3.with-data-migration","i-lucide-database-backup",{"title":274,"path":275,"stem":276,"children":277,"icon":279},"Reference","\u002Fdocs\u002Freference","1.docs\u002F8.reference\u002F1.index",[278,280,285,290,295,300,305,309],{"title":274,"path":275,"stem":276,"icon":279},"i-lucide-list",{"title":281,"path":282,"stem":283,"icon":284},"Configuration reference","\u002Fdocs\u002Freference\u002Fconfiguration-reference","1.docs\u002F8.reference\u002F2.configuration-reference","i-lucide-table",{"title":286,"path":287,"stem":288,"icon":289},"REST API reference","\u002Fdocs\u002Freference\u002Frest-api-reference","1.docs\u002F8.reference\u002F3.rest-api-reference","i-lucide-network",{"title":291,"path":292,"stem":293,"icon":294},"Gradle plugin reference","\u002Fdocs\u002Freference\u002Fgradle-plugin-reference","1.docs\u002F8.reference\u002F4.gradle-plugin-reference","i-lucide-box",{"title":296,"path":297,"stem":298,"icon":299},"Maven reference","\u002Fdocs\u002Freference\u002Fmaven-reference","1.docs\u002F8.reference\u002F5.maven-reference","i-simple-icons-apachemaven",{"title":301,"path":302,"stem":303,"icon":304},"Kafka Streams compatibility matrix","\u002Fdocs\u002Freference\u002Fks-compatibility-matrix","1.docs\u002F8.reference\u002F6.ks-compatibility-matrix","i-lucide-table-2",{"title":306,"path":307,"stem":308,"icon":170},"Metrics reference","\u002Fdocs\u002Freference\u002Fmetrics-reference","1.docs\u002F8.reference\u002F7.metrics-reference",{"title":310,"path":311,"stem":312,"icon":313},"Glossary","\u002Fdocs\u002Freference\u002Fglossary","1.docs\u002F8.reference\u002F8.glossary","i-lucide-book-a",{"id":315,"title":92,"body":316,"description":2407,"extension":2408,"meta":2409,"navigation":2410,"pageType":2411,"path":88,"seo":2412,"stem":89,"__hash__":2413},"docs\u002F1.docs\u002F3.building\u002F1.index.md",{"type":317,"value":318,"toc":2401},"minimark",[319,348,351,415,420,455,466,469,1168,1201,1216,1220,1223,1387,1402,1423,1427,1430,1456,1567,1573,2201,2225,2257,2261,2264,2392,2397],[320,321,322,323,327,328,332,333,336,337,336,340,343,344,347],"p",{},"A ",[324,325,326],"strong",{},"topology"," is the processing graph your application runs: source topics in, operators in the middle, sink topics out. You describe it once with ",[329,330,331],"code",{},"StreamsBuilder",", hand the builder to the runtime, and the engine executes it. The DSL is Kafka Streams compatible — if you know ",[329,334,335],{},"stream()",", ",[329,338,339],{},"mapValues()",[329,341,342],{},"groupBy()",", and ",[329,345,346],{},"to()",", you already know how to write one.",[320,349,350],{},"This page is the orientation for the section: the entry point, the stream abstractions at a glance, and the one rule that trips up people coming from Kafka Streams — the fan-out rule. Each operator family has its own page; links are at the bottom.",[352,353,354],"tldr-panel",{},[355,356,357,379,398],"ul",{},[358,359,360,363,364,366,367,370,371,374,375,378],"li",{},[324,361,362],{},"Entry point:"," ",[329,365,331],{}," — call ",[329,368,369],{},".stream(...)"," \u002F ",[329,372,373],{},".table(...)"," to read, chain operators, call ",[329,376,377],{},".to(...)"," to write.",[358,380,381,363,384,387,388,391,392,370,394,397],{},[324,382,383],{},"Abstractions:",[329,385,386],{},"KStream"," (event stream), ",[329,389,390],{},"KTable"," (changelog table), and the grouped\u002Fwindowed types you reach via ",[329,393,342],{},[329,395,396],{},"windowedBy()",".",[358,399,400,403,404,410,411,414],{},[324,401,402],{},"Fan-out rule:"," to branch a stream multiple ways, ",[324,405,406,407,409],{},"reuse the same ",[329,408,386],{}," reference",". Calling ",[329,412,413],{},"builder.stream()"," twice on the same topic is rejected at build time.",[416,417,419],"h2",{"id":418},"streamsbuilder-the-entry-point","StreamsBuilder — the entry point",[320,421,422,423,425,426,336,429,336,432,336,435,438,439,336,442,336,445,448,449,451,452,454],{},"Everything starts with a ",[329,424,331],{},". Its source methods (",[329,427,428],{},"stream",[329,430,431],{},"table",[329,433,434],{},"globalTable",[329,436,437],{},"scheduled",") return DSL objects you chain operators onto; terminal operations (",[329,440,441],{},"to",[329,443,444],{},"forEach",[329,446,447],{},"print",") end a branch and return nothing. You never construct ",[329,450,386],{}," or ",[329,453,390],{}," directly — the builder hands them to you.",[320,456,457,458,461,462,465],{},"A source method takes a topic name and an optional ",[329,459,460],{},"Consumed"," for serdes, watermark strategy, and offset-reset policy. Every operator takes an optional ",[329,463,464],{},"Named"," so its node gets a stable identity in the topology graph, metrics, and state-store names. The convention across the examples is to name each operator explicitly.",[320,467,468],{},"Here is a minimal end-to-end topology — read, transform, filter, write:",[470,471,473,765],"code-tabs",{"group":472},"lang",[474,475,481],"pre",{"className":476,"code":477,"filename":478,"language":479,"meta":480,"style":480},"language-kotlin shiki shiki-themes vitesse-light","import io.stoatflow.core.topology.Consumed\nimport io.stoatflow.core.topology.Named\nimport io.stoatflow.core.topology.Produced\nimport io.stoatflow.core.topology.StreamsBuilder\nimport org.apache.kafka.common.serialization.Serdes\n\nfun buildTopology(builder: StreamsBuilder) {\n    builder\n        .stream\u003CString, String>(\"input-topic\", Consumed.`as`(\"source\"))\n        .mapValues({ value -> value.uppercase() }, Named.`as`(\"upper\"))\n        .filter({ _, value -> value.length > 5 }, Named.`as`(\"longer-than-5\"))\n        .to(\n            \"output-topic\",\n            Produced.`as`\u003CString, String>(\"sink\")\n                .withKeySerde(Serdes.String())\n                .withValueSerde(Serdes.String()),\n        )\n}\n","Kotlin","kotlin","",[329,482,483,496,504,512,520,528,535,554,560,600,639,678,688,697,721,738,753,759],{"__ignoreMap":480},[484,485,488,492],"span",{"class":486,"line":487},"line",1,[484,489,491],{"class":490},"sbBg2","import",[484,493,495],{"class":494},"sySUi"," io.stoatflow.core.topology.Consumed\n",[484,497,499,501],{"class":486,"line":498},2,[484,500,491],{"class":490},[484,502,503],{"class":494}," io.stoatflow.core.topology.Named\n",[484,505,507,509],{"class":486,"line":506},3,[484,508,491],{"class":490},[484,510,511],{"class":494}," io.stoatflow.core.topology.Produced\n",[484,513,515,517],{"class":486,"line":514},4,[484,516,491],{"class":490},[484,518,519],{"class":494}," io.stoatflow.core.topology.StreamsBuilder\n",[484,521,523,525],{"class":486,"line":522},5,[484,524,491],{"class":490},[484,526,527],{"class":494}," org.apache.kafka.common.serialization.Serdes\n",[484,529,531],{"class":486,"line":530},6,[484,532,534],{"emptyLinePlaceholder":533},true,"\n",[484,536,538,541,544,548,551],{"class":486,"line":537},7,[484,539,540],{"class":490},"fun",[484,542,543],{"class":494}," buildTopology",[484,545,547],{"class":546},"suHK_","(builder: ",[484,549,331],{"class":550},"sUxyF",[484,552,553],{"class":546},") {\n",[484,555,557],{"class":486,"line":556},8,[484,558,559],{"class":546},"    builder\n",[484,561,563,566,568,571,574,576,578,581,585,588,591,594,597],{"class":486,"line":562},9,[484,564,565],{"class":546},"        .",[484,567,428],{"class":494},[484,569,570],{"class":546},"\u003C",[484,572,573],{"class":550},"String",[484,575,336],{"class":546},[484,577,573],{"class":550},[484,579,580],{"class":546},">(",[484,582,584],{"class":583},"spphp","\"input-topic\"",[484,586,587],{"class":546},", Consumed.",[484,589,590],{"class":494},"`as`",[484,592,593],{"class":546},"(",[484,595,596],{"class":583},"\"source\"",[484,598,599],{"class":546},"))\n",[484,601,603,605,608,611,615,619,622,624,627,630,632,634,637],{"class":486,"line":602},10,[484,604,565],{"class":546},[484,606,607],{"class":494},"mapValues",[484,609,610],{"class":546},"({ ",[484,612,614],{"class":613},"si04Y","value",[484,616,618],{"class":617},"sYZai"," ->",[484,620,621],{"class":613}," value",[484,623,397],{"class":546},[484,625,626],{"class":494},"uppercase",[484,628,629],{"class":546},"() }, Named.",[484,631,590],{"class":494},[484,633,593],{"class":546},[484,635,636],{"class":583},"\"upper\"",[484,638,599],{"class":546},[484,640,642,644,647,650,652,654,656,659,662,666,669,671,673,676],{"class":486,"line":641},11,[484,643,565],{"class":546},[484,645,646],{"class":494},"filter",[484,648,649],{"class":546},"({ _, ",[484,651,614],{"class":613},[484,653,618],{"class":617},[484,655,621],{"class":613},[484,657,658],{"class":546},".length ",[484,660,661],{"class":613},">",[484,663,665],{"class":664},"s-TwI"," 5",[484,667,668],{"class":546}," }, Named.",[484,670,590],{"class":494},[484,672,593],{"class":546},[484,674,675],{"class":583},"\"longer-than-5\"",[484,677,599],{"class":546},[484,679,681,683,685],{"class":486,"line":680},12,[484,682,565],{"class":546},[484,684,441],{"class":494},[484,686,687],{"class":546},"(\n",[484,689,691,694],{"class":486,"line":690},13,[484,692,693],{"class":583},"            \"output-topic\"",[484,695,696],{"class":546},",\n",[484,698,700,703,705,707,709,711,713,715,718],{"class":486,"line":699},14,[484,701,702],{"class":546},"            Produced.",[484,704,590],{"class":494},[484,706,570],{"class":546},[484,708,573],{"class":550},[484,710,336],{"class":546},[484,712,573],{"class":550},[484,714,580],{"class":546},[484,716,717],{"class":583},"\"sink\"",[484,719,720],{"class":546},")\n",[484,722,724,727,730,733,735],{"class":486,"line":723},15,[484,725,726],{"class":546},"                .",[484,728,729],{"class":494},"withKeySerde",[484,731,732],{"class":546},"(Serdes.",[484,734,573],{"class":494},[484,736,737],{"class":546},"())\n",[484,739,741,743,746,748,750],{"class":486,"line":740},16,[484,742,726],{"class":546},[484,744,745],{"class":494},"withValueSerde",[484,747,732],{"class":546},[484,749,573],{"class":494},[484,751,752],{"class":546},"()),\n",[484,754,756],{"class":486,"line":755},17,[484,757,758],{"class":546},"        )\n",[484,760,762],{"class":486,"line":761},18,[484,763,764],{"class":546},"}\n",[474,766,771],{"className":767,"code":768,"filename":769,"language":770,"meta":480,"style":480},"language-java shiki shiki-themes vitesse-light","import io.stoatflow.core.topology.Consumed;\nimport io.stoatflow.core.topology.Named;\nimport io.stoatflow.core.topology.Produced;\nimport io.stoatflow.core.topology.StreamsBuilder;\nimport org.apache.kafka.common.serialization.Serdes;\n\nvoid buildTopology(StreamsBuilder builder) {\n    builder\n        .\u003CString, String>stream(\"input-topic\", Consumed.as(\"source\"))\n        .mapValues(value -> value.toUpperCase(), Named.as(\"upper\"))\n        .filter((key, value) -> value.length() > 5, Named.as(\"longer-than-5\"))\n        .to(\n            \"output-topic\",\n            Produced.\u003CString, String>as(\"sink\")\n                .withKeySerde(Serdes.String())\n                .withValueSerde(Serdes.String()));\n}\n","Java","java",[329,772,773,801,825,850,874,908,912,930,934,985,1027,1081,1089,1101,1131,1147,1164],{"__ignoreMap":480},[484,774,775,777,780,782,785,787,790,792,794,796,798],{"class":486,"line":487},[484,776,491],{"class":490},[484,778,779],{"class":546}," io",[484,781,397],{"class":617},[484,783,784],{"class":546},"stoatflow",[484,786,397],{"class":617},[484,788,789],{"class":546},"core",[484,791,397],{"class":617},[484,793,326],{"class":546},[484,795,397],{"class":617},[484,797,460],{"class":546},[484,799,800],{"class":617},";\n",[484,802,803,805,807,809,811,813,815,817,819,821,823],{"class":486,"line":498},[484,804,491],{"class":490},[484,806,779],{"class":546},[484,808,397],{"class":617},[484,810,784],{"class":546},[484,812,397],{"class":617},[484,814,789],{"class":546},[484,816,397],{"class":617},[484,818,326],{"class":546},[484,820,397],{"class":617},[484,822,464],{"class":546},[484,824,800],{"class":617},[484,826,827,829,831,833,835,837,839,841,843,845,848],{"class":486,"line":506},[484,828,491],{"class":490},[484,830,779],{"class":546},[484,832,397],{"class":617},[484,834,784],{"class":546},[484,836,397],{"class":617},[484,838,789],{"class":546},[484,840,397],{"class":617},[484,842,326],{"class":546},[484,844,397],{"class":617},[484,846,847],{"class":546},"Produced",[484,849,800],{"class":617},[484,851,852,854,856,858,860,862,864,866,868,870,872],{"class":486,"line":514},[484,853,491],{"class":490},[484,855,779],{"class":546},[484,857,397],{"class":617},[484,859,784],{"class":546},[484,861,397],{"class":617},[484,863,789],{"class":546},[484,865,397],{"class":617},[484,867,326],{"class":546},[484,869,397],{"class":617},[484,871,331],{"class":546},[484,873,800],{"class":617},[484,875,876,878,881,883,886,888,891,893,896,898,901,903,906],{"class":486,"line":522},[484,877,491],{"class":490},[484,879,880],{"class":546}," org",[484,882,397],{"class":617},[484,884,885],{"class":546},"apache",[484,887,397],{"class":617},[484,889,890],{"class":546},"kafka",[484,892,397],{"class":617},[484,894,895],{"class":546},"common",[484,897,397],{"class":617},[484,899,900],{"class":546},"serialization",[484,902,397],{"class":617},[484,904,905],{"class":546},"Serdes",[484,907,800],{"class":617},[484,909,910],{"class":486,"line":530},[484,911,534],{"emptyLinePlaceholder":533},[484,913,914,917,919,921,924,927],{"class":486,"line":537},[484,915,916],{"class":613},"void",[484,918,543],{"class":494},[484,920,593],{"class":617},[484,922,923],{"class":546},"StreamsBuilder builder",[484,925,926],{"class":617},")",[484,928,929],{"class":617}," {\n",[484,931,932],{"class":486,"line":556},[484,933,559],{"class":546},[484,935,936,938,940,942,945,948,950,952,954,958,961,963,965,969,971,974,976,978,981,983],{"class":486,"line":562},[484,937,565],{"class":617},[484,939,570],{"class":613},[484,941,573],{"class":546},[484,943,944],{"class":617},",",[484,946,947],{"class":546}," String",[484,949,661],{"class":613},[484,951,428],{"class":494},[484,953,593],{"class":617},[484,955,957],{"class":956},"sSP4y","\"",[484,959,960],{"class":583},"input-topic",[484,962,957],{"class":956},[484,964,944],{"class":617},[484,966,968],{"class":967},"svycV"," Consumed",[484,970,397],{"class":617},[484,972,973],{"class":494},"as",[484,975,593],{"class":617},[484,977,957],{"class":956},[484,979,980],{"class":583},"source",[484,982,957],{"class":956},[484,984,599],{"class":617},[484,986,987,989,991,993,996,999,1001,1003,1006,1009,1012,1014,1016,1018,1020,1023,1025],{"class":486,"line":602},[484,988,565],{"class":617},[484,990,607],{"class":494},[484,992,593],{"class":617},[484,994,995],{"class":546},"value ",[484,997,998],{"class":617},"->",[484,1000,621],{"class":967},[484,1002,397],{"class":617},[484,1004,1005],{"class":494},"toUpperCase",[484,1007,1008],{"class":617},"(),",[484,1010,1011],{"class":967}," Named",[484,1013,397],{"class":617},[484,1015,973],{"class":494},[484,1017,593],{"class":617},[484,1019,957],{"class":956},[484,1021,1022],{"class":583},"upper",[484,1024,957],{"class":956},[484,1026,599],{"class":617},[484,1028,1029,1031,1033,1036,1039,1041,1043,1045,1047,1049,1051,1054,1057,1060,1062,1064,1066,1068,1070,1072,1074,1077,1079],{"class":486,"line":641},[484,1030,565],{"class":617},[484,1032,646],{"class":494},[484,1034,1035],{"class":617},"((",[484,1037,1038],{"class":546},"key",[484,1040,944],{"class":617},[484,1042,621],{"class":546},[484,1044,926],{"class":617},[484,1046,618],{"class":617},[484,1048,621],{"class":967},[484,1050,397],{"class":617},[484,1052,1053],{"class":494},"length",[484,1055,1056],{"class":617},"()",[484,1058,1059],{"class":613}," >",[484,1061,665],{"class":664},[484,1063,944],{"class":617},[484,1065,1011],{"class":967},[484,1067,397],{"class":617},[484,1069,973],{"class":494},[484,1071,593],{"class":617},[484,1073,957],{"class":956},[484,1075,1076],{"class":583},"longer-than-5",[484,1078,957],{"class":956},[484,1080,599],{"class":617},[484,1082,1083,1085,1087],{"class":486,"line":680},[484,1084,565],{"class":617},[484,1086,441],{"class":494},[484,1088,687],{"class":617},[484,1090,1091,1094,1097,1099],{"class":486,"line":690},[484,1092,1093],{"class":956},"            \"",[484,1095,1096],{"class":583},"output-topic",[484,1098,957],{"class":956},[484,1100,696],{"class":617},[484,1102,1103,1106,1108,1110,1112,1114,1116,1118,1120,1122,1124,1127,1129],{"class":486,"line":699},[484,1104,1105],{"class":546},"            Produced",[484,1107,397],{"class":617},[484,1109,570],{"class":613},[484,1111,573],{"class":546},[484,1113,944],{"class":617},[484,1115,947],{"class":546},[484,1117,661],{"class":613},[484,1119,973],{"class":494},[484,1121,593],{"class":617},[484,1123,957],{"class":956},[484,1125,1126],{"class":583},"sink",[484,1128,957],{"class":956},[484,1130,720],{"class":617},[484,1132,1133,1135,1137,1139,1141,1143,1145],{"class":486,"line":723},[484,1134,726],{"class":617},[484,1136,729],{"class":494},[484,1138,593],{"class":617},[484,1140,905],{"class":967},[484,1142,397],{"class":617},[484,1144,573],{"class":494},[484,1146,737],{"class":617},[484,1148,1149,1151,1153,1155,1157,1159,1161],{"class":486,"line":740},[484,1150,726],{"class":617},[484,1152,745],{"class":494},[484,1154,593],{"class":617},[484,1156,905],{"class":967},[484,1158,397],{"class":617},[484,1160,573],{"class":494},[484,1162,1163],{"class":617},"()));\n",[484,1165,1166],{"class":486,"line":755},[484,1167,764],{"class":617},[1169,1170,1173],"callout",{"color":1171,"icon":1172},"info","i-lucide-info",[320,1174,1175,1177,1178,1181,1182,1185,1186,1189,1190,1193,1194,1197,1198,397],{},[329,1176,973],{}," is a soft keyword in Kotlin, so the factory methods are written ",[329,1179,1180],{},"Consumed.`as`(...)"," with backticks. In Java it's plain ",[329,1183,1184],{},"Consumed.as(...)",". Imports come from ",[329,1187,1188],{},"io.stoatflow.core.*"," (DSL) and ",[329,1191,1192],{},"io.stoatflow.runtime.*"," (runtime wrapper). See ",[1195,1196,28],"a",{"href":29}," for the full runnable shell that calls ",[329,1199,1200],{},"buildTopology",[320,1202,1203,1204,1207,1208,1211,1212,1215],{},"When you're done describing the graph, the builder is what you pass to the runtime — ",[329,1205,1206],{},"StoatFlowRuntime.fromConfig(topologyBuilder = { buildTopology(it) }, ...)",". The runtime calls ",[329,1209,1210],{},"build()"," for you and validates the topology before it starts. (If you're embedding the core engine directly rather than using the runtime wrapper, you call ",[329,1213,1214],{},"builder.build()"," yourself.)",[416,1217,1219],{"id":1218},"the-stream-abstractions-at-a-glance","The stream abstractions at a glance",[320,1221,1222],{},"The DSL has two foundational types and several specialised ones you reach by grouping or windowing:",[431,1224,1225,1241],{},[1226,1227,1228],"thead",{},[1229,1230,1231,1235,1238],"tr",{},[1232,1233,1234],"th",{},"Type",[1232,1236,1237],{},"What it is",[1232,1239,1240],{},"You get it from",[1242,1243,1244,1266,1287,1305,1320,1342,1357,1372],"tbody",{},[1229,1245,1246,1252,1255],{},[1247,1248,1249],"td",{},[329,1250,1251],{},"KStream\u003CK, V>",[1247,1253,1254],{},"An unbounded stream of independent events. Each record is a fact.",[1247,1256,1257,336,1260,336,1263],{},[329,1258,1259],{},"builder.stream(...)",[329,1261,1262],{},"KTable.toStream()",[329,1264,1265],{},"builder.scheduled(...)",[1229,1267,1268,1273,1276],{},[1247,1269,1270],{},[329,1271,1272],{},"KTable\u003CK, V>",[1247,1274,1275],{},"A changelog table — one current value per key. A new record for a key replaces the previous one.",[1247,1277,1278,336,1281,336,1284],{},[329,1279,1280],{},"builder.table(...)",[329,1282,1283],{},"KGroupedStream.count()\u002Freduce()",[329,1285,1286],{},"KStream.toTable()",[1229,1288,1289,1294,1297],{},[1247,1290,1291],{},[329,1292,1293],{},"KGroupedStream\u003CK, V>",[1247,1295,1296],{},"A stream re-grouped by key, ready to aggregate.",[1247,1298,1299,370,1302],{},[329,1300,1301],{},"KStream.groupBy(...)",[329,1303,1304],{},"groupByKey()",[1229,1306,1307,1312,1315],{},[1247,1308,1309],{},[329,1310,1311],{},"KGroupedTable\u003CK, V>",[1247,1313,1314],{},"A table re-grouped by key, with add\u002Fsubtract changelog semantics.",[1247,1316,1317],{},[329,1318,1319],{},"KTable.groupBy(...)",[1229,1321,1322,1327,1334],{},[1247,1323,1324],{},[329,1325,1326],{},"TimeWindowedKStream\u003CK, V>",[1247,1328,1329,1330,1333],{},"A grouped stream bucketed into fixed-size time windows (tumbling\u002Fhopping) ",[324,1331,1332],{},"or"," event-driven sliding windows (KIP-450).",[1247,1335,1336,370,1339],{},[329,1337,1338],{},"KGroupedStream.windowedBy(TimeWindows...)",[329,1340,1341],{},"windowedBy(SlidingWindows...)",[1229,1343,1344,1349,1352],{},[1247,1345,1346],{},[329,1347,1348],{},"SessionWindowedKStream\u003CK, V>",[1247,1350,1351],{},"A grouped stream bucketed by activity gaps.",[1247,1353,1354],{},[329,1355,1356],{},"KGroupedStream.windowedBy(SessionWindows...)",[1229,1358,1359,1364,1367],{},[1247,1360,1361],{},[329,1362,1363],{},"CogroupedKStream\u003CK, V>",[1247,1365,1366],{},"Multiple streams aggregated jointly into one result.",[1247,1368,1369],{},[329,1370,1371],{},"KGroupedStream.cogroup(...)",[1229,1373,1374,1379,1382],{},[1247,1375,1376],{},[329,1377,1378],{},"BranchedKStream\u003CK, V>",[1247,1380,1381],{},"The result of splitting one stream into named, predicate-routed branches.",[1247,1383,1384],{},[329,1385,1386],{},"KStream.split(...)",[320,1388,1389,1392,1393,1396,1397,1399,1400,397],{},[329,1390,1391],{},"StoatFlow"," also adds ",[324,1394,1395],{},"scheduled sources"," — a source that emits records on an interval or cron schedule instead of consuming a topic. It returns a ",[329,1398,386],{}," and flows through the topology like any other source. See ",[1195,1401,140],{"href":141},[320,1403,1404,1405,1407,1408,1410,1411,1414,1415,1417,1418,1420,1421,397],{},"The mental model is the same as Kafka Streams: a ",[329,1406,386],{}," is a stream of events; a ",[329,1409,390],{}," is the latest-value-per-key view of a changelog. ",[329,1412,1413],{},"KStream.toStream()"," doesn't exist (it's already a stream), but ",[329,1416,1262],{}," turns a table back into its change events, and ",[329,1419,1286],{}," materialises a stream as a table. For the full operator-by-operator parity status against Kafka Streams, see the ",[1195,1422,301],{"href":302},[416,1424,1426],{"id":1425},"the-fan-out-rule","The fan-out rule",[320,1428,1429],{},"This is the one rule worth internalising before you write anything non-trivial.",[320,1431,1432,1433,1436,1437,1441,1442,1445,1446,1448,1449,1452,1453,397],{},"To send one input stream down ",[324,1434,1435],{},"multiple"," processing paths — say, one branch to topic A and another to topic B — you ",[324,1438,406,1439,409],{},[329,1440,386],{}," for each branch. You do ",[324,1443,1444],{},"not"," call ",[329,1447,413],{}," twice on the same topic. Subscribing the same topic from two source nodes is ",[324,1450,1451],{},"rejected when the topology is built",", with a ",[329,1454,1455],{},"TopologyValidationException",[1169,1457,1459,1465,1558],{"color":1458,"icon":98},"error",[320,1460,1461,1464],{},[324,1462,1463],{},"Don't do this"," — two source nodes on one topic:",[474,1466,1468],{"className":476,"code":1467,"language":479,"meta":480,"style":480},"builder.stream\u003CString, String>(\"orders\").filter(...).to(\"a\")   \u002F\u002F source node 1\nbuilder.stream\u003CString, String>(\"orders\").mapValues(...).to(\"b\") \u002F\u002F source node 2 — REJECTED at build()\n",[329,1469,1470,1517],{"__ignoreMap":480},[484,1471,1472,1475,1477,1479,1481,1483,1485,1487,1490,1493,1495,1497,1500,1503,1505,1507,1510,1513],{"class":486,"line":487},[484,1473,1474],{"class":546},"builder.",[484,1476,428],{"class":494},[484,1478,570],{"class":546},[484,1480,573],{"class":550},[484,1482,336],{"class":546},[484,1484,573],{"class":550},[484,1486,580],{"class":546},[484,1488,1489],{"class":583},"\"orders\"",[484,1491,1492],{"class":546},").",[484,1494,646],{"class":494},[484,1496,593],{"class":546},[484,1498,1499],{"class":613},"..",[484,1501,1502],{"class":546},".).",[484,1504,441],{"class":494},[484,1506,593],{"class":546},[484,1508,1509],{"class":583},"\"a\"",[484,1511,1512],{"class":546},")   ",[484,1514,1516],{"class":1515},"s8zF2","\u002F\u002F source node 1\n",[484,1518,1519,1521,1523,1525,1527,1529,1531,1533,1535,1537,1539,1541,1543,1545,1547,1549,1552,1555],{"class":486,"line":498},[484,1520,1474],{"class":546},[484,1522,428],{"class":494},[484,1524,570],{"class":546},[484,1526,573],{"class":550},[484,1528,336],{"class":546},[484,1530,573],{"class":550},[484,1532,580],{"class":546},[484,1534,1489],{"class":583},[484,1536,1492],{"class":546},[484,1538,607],{"class":494},[484,1540,593],{"class":546},[484,1542,1499],{"class":613},[484,1544,1502],{"class":546},[484,1546,441],{"class":494},[484,1548,593],{"class":546},[484,1550,1551],{"class":583},"\"b\"",[484,1553,1554],{"class":546},") ",[484,1556,1557],{"class":1515},"\u002F\u002F source node 2 — REJECTED at build()\n",[320,1559,1560,1562,1563],{},[329,1561,1210],{}," throws: ",[1564,1565,1566],"em",{},"\"Multiple source nodes consuming the same topic are not supported.\"",[320,1568,1569,1570,1572],{},"Instead, hold the source ",[329,1571,386],{}," in a variable and branch off it. Each operator chain that starts from the shared reference is an independent path through the topology; they all share the single source subscription:",[470,1574,1575,1812],{"group":472},[474,1576,1578],{"className":476,"code":1577,"filename":478,"language":479,"meta":480,"style":480},"import io.stoatflow.core.topology.Consumed\nimport io.stoatflow.core.topology.KStream\nimport io.stoatflow.core.topology.Named\nimport io.stoatflow.core.topology.Produced\nimport io.stoatflow.core.topology.StreamsBuilder\n\nfun buildTopology(builder: StreamsBuilder) {\n    \u002F\u002F Read the topic ONCE, keep the reference.\n    val orders: KStream\u003CString, String> =\n        builder.stream(\"orders\", Consumed.`as`(\"source\"))\n\n    \u002F\u002F Branch 1: filter, write to \"large-orders\".\n    orders\n        .filter({ _, v -> v.length > 100 }, Named.`as`(\"only-large\"))\n        .to(\"large-orders\", Produced.`as`(\"large-sink\"))\n\n    \u002F\u002F Branch 2: transform the SAME source, write to \"orders-upper\".\n    orders\n        .mapValues({ v -> v.uppercase() }, Named.`as`(\"upper\"))\n        .to(\"orders-upper\", Produced.`as`(\"upper-sink\"))\n}\n",[329,1579,1580,1586,1593,1599,1605,1611,1615,1627,1632,1656,1677,1681,1686,1691,1721,1744,1748,1753,1757,1784,1807],{"__ignoreMap":480},[484,1581,1582,1584],{"class":486,"line":487},[484,1583,491],{"class":490},[484,1585,495],{"class":494},[484,1587,1588,1590],{"class":486,"line":498},[484,1589,491],{"class":490},[484,1591,1592],{"class":494}," io.stoatflow.core.topology.KStream\n",[484,1594,1595,1597],{"class":486,"line":506},[484,1596,491],{"class":490},[484,1598,503],{"class":494},[484,1600,1601,1603],{"class":486,"line":514},[484,1602,491],{"class":490},[484,1604,511],{"class":494},[484,1606,1607,1609],{"class":486,"line":522},[484,1608,491],{"class":490},[484,1610,519],{"class":494},[484,1612,1613],{"class":486,"line":530},[484,1614,534],{"emptyLinePlaceholder":533},[484,1616,1617,1619,1621,1623,1625],{"class":486,"line":537},[484,1618,540],{"class":490},[484,1620,543],{"class":494},[484,1622,547],{"class":546},[484,1624,331],{"class":550},[484,1626,553],{"class":546},[484,1628,1629],{"class":486,"line":556},[484,1630,1631],{"class":1515},"    \u002F\u002F Read the topic ONCE, keep the reference.\n",[484,1633,1634,1637,1640,1642,1644,1646,1648,1650,1653],{"class":486,"line":562},[484,1635,1636],{"class":490},"    val",[484,1638,1639],{"class":546}," orders: ",[484,1641,386],{"class":550},[484,1643,570],{"class":546},[484,1645,573],{"class":550},[484,1647,336],{"class":546},[484,1649,573],{"class":550},[484,1651,1652],{"class":546},"> ",[484,1654,1655],{"class":617},"=\n",[484,1657,1658,1661,1663,1665,1667,1669,1671,1673,1675],{"class":486,"line":602},[484,1659,1660],{"class":546},"        builder.",[484,1662,428],{"class":494},[484,1664,593],{"class":546},[484,1666,1489],{"class":583},[484,1668,587],{"class":546},[484,1670,590],{"class":494},[484,1672,593],{"class":546},[484,1674,596],{"class":583},[484,1676,599],{"class":546},[484,1678,1679],{"class":486,"line":641},[484,1680,534],{"emptyLinePlaceholder":533},[484,1682,1683],{"class":486,"line":680},[484,1684,1685],{"class":1515},"    \u002F\u002F Branch 1: filter, write to \"large-orders\".\n",[484,1687,1688],{"class":486,"line":690},[484,1689,1690],{"class":546},"    orders\n",[484,1692,1693,1695,1697,1700,1702,1705,1707,1710,1712,1714,1716,1719],{"class":486,"line":699},[484,1694,565],{"class":546},[484,1696,646],{"class":494},[484,1698,1699],{"class":546},"({ _, v ",[484,1701,998],{"class":617},[484,1703,1704],{"class":546}," v.length ",[484,1706,661],{"class":613},[484,1708,1709],{"class":664}," 100",[484,1711,668],{"class":546},[484,1713,590],{"class":494},[484,1715,593],{"class":546},[484,1717,1718],{"class":583},"\"only-large\"",[484,1720,599],{"class":546},[484,1722,1723,1725,1727,1729,1732,1735,1737,1739,1742],{"class":486,"line":723},[484,1724,565],{"class":546},[484,1726,441],{"class":494},[484,1728,593],{"class":546},[484,1730,1731],{"class":583},"\"large-orders\"",[484,1733,1734],{"class":546},", Produced.",[484,1736,590],{"class":494},[484,1738,593],{"class":546},[484,1740,1741],{"class":583},"\"large-sink\"",[484,1743,599],{"class":546},[484,1745,1746],{"class":486,"line":740},[484,1747,534],{"emptyLinePlaceholder":533},[484,1749,1750],{"class":486,"line":755},[484,1751,1752],{"class":1515},"    \u002F\u002F Branch 2: transform the SAME source, write to \"orders-upper\".\n",[484,1754,1755],{"class":486,"line":761},[484,1756,1690],{"class":546},[484,1758,1760,1762,1764,1767,1769,1772,1774,1776,1778,1780,1782],{"class":486,"line":1759},19,[484,1761,565],{"class":546},[484,1763,607],{"class":494},[484,1765,1766],{"class":546},"({ v ",[484,1768,998],{"class":617},[484,1770,1771],{"class":546}," v.",[484,1773,626],{"class":494},[484,1775,629],{"class":546},[484,1777,590],{"class":494},[484,1779,593],{"class":546},[484,1781,636],{"class":583},[484,1783,599],{"class":546},[484,1785,1787,1789,1791,1793,1796,1798,1800,1802,1805],{"class":486,"line":1786},20,[484,1788,565],{"class":546},[484,1790,441],{"class":494},[484,1792,593],{"class":546},[484,1794,1795],{"class":583},"\"orders-upper\"",[484,1797,1734],{"class":546},[484,1799,590],{"class":494},[484,1801,593],{"class":546},[484,1803,1804],{"class":583},"\"upper-sink\"",[484,1806,599],{"class":546},[484,1808,1810],{"class":486,"line":1809},21,[484,1811,764],{"class":546},[474,1813,1815],{"className":767,"code":1814,"filename":769,"language":770,"meta":480,"style":480},"import io.stoatflow.core.topology.Consumed;\nimport io.stoatflow.core.topology.KStream;\nimport io.stoatflow.core.topology.Named;\nimport io.stoatflow.core.topology.Produced;\nimport io.stoatflow.core.topology.StreamsBuilder;\n\nvoid buildTopology(StreamsBuilder builder) {\n    \u002F\u002F Read the topic ONCE, keep the reference.\n    KStream\u003CString, String> orders =\n        builder.stream(\"orders\", Consumed.as(\"source\"));\n\n    \u002F\u002F Branch 1: filter, write to \"large-orders\".\n    orders\n        .filter((key, v) -> v.length() > 100, Named.as(\"only-large\"))\n        .to(\"large-orders\", Produced.as(\"large-sink\"));\n\n    \u002F\u002F Branch 2: transform the SAME source, write to \"orders-upper\".\n    orders\n        .mapValues(v -> v.toUpperCase(), Named.as(\"upper\"))\n        .to(\"orders-upper\", Produced.as(\"upper-sink\"));\n}\n",[329,1816,1817,1841,1865,1889,1913,1937,1941,1955,1959,1980,2017,2021,2025,2029,2079,2114,2118,2122,2126,2163,2197],{"__ignoreMap":480},[484,1818,1819,1821,1823,1825,1827,1829,1831,1833,1835,1837,1839],{"class":486,"line":487},[484,1820,491],{"class":490},[484,1822,779],{"class":546},[484,1824,397],{"class":617},[484,1826,784],{"class":546},[484,1828,397],{"class":617},[484,1830,789],{"class":546},[484,1832,397],{"class":617},[484,1834,326],{"class":546},[484,1836,397],{"class":617},[484,1838,460],{"class":546},[484,1840,800],{"class":617},[484,1842,1843,1845,1847,1849,1851,1853,1855,1857,1859,1861,1863],{"class":486,"line":498},[484,1844,491],{"class":490},[484,1846,779],{"class":546},[484,1848,397],{"class":617},[484,1850,784],{"class":546},[484,1852,397],{"class":617},[484,1854,789],{"class":546},[484,1856,397],{"class":617},[484,1858,326],{"class":546},[484,1860,397],{"class":617},[484,1862,386],{"class":546},[484,1864,800],{"class":617},[484,1866,1867,1869,1871,1873,1875,1877,1879,1881,1883,1885,1887],{"class":486,"line":506},[484,1868,491],{"class":490},[484,1870,779],{"class":546},[484,1872,397],{"class":617},[484,1874,784],{"class":546},[484,1876,397],{"class":617},[484,1878,789],{"class":546},[484,1880,397],{"class":617},[484,1882,326],{"class":546},[484,1884,397],{"class":617},[484,1886,464],{"class":546},[484,1888,800],{"class":617},[484,1890,1891,1893,1895,1897,1899,1901,1903,1905,1907,1909,1911],{"class":486,"line":514},[484,1892,491],{"class":490},[484,1894,779],{"class":546},[484,1896,397],{"class":617},[484,1898,784],{"class":546},[484,1900,397],{"class":617},[484,1902,789],{"class":546},[484,1904,397],{"class":617},[484,1906,326],{"class":546},[484,1908,397],{"class":617},[484,1910,847],{"class":546},[484,1912,800],{"class":617},[484,1914,1915,1917,1919,1921,1923,1925,1927,1929,1931,1933,1935],{"class":486,"line":522},[484,1916,491],{"class":490},[484,1918,779],{"class":546},[484,1920,397],{"class":617},[484,1922,784],{"class":546},[484,1924,397],{"class":617},[484,1926,789],{"class":546},[484,1928,397],{"class":617},[484,1930,326],{"class":546},[484,1932,397],{"class":617},[484,1934,331],{"class":546},[484,1936,800],{"class":617},[484,1938,1939],{"class":486,"line":530},[484,1940,534],{"emptyLinePlaceholder":533},[484,1942,1943,1945,1947,1949,1951,1953],{"class":486,"line":537},[484,1944,916],{"class":613},[484,1946,543],{"class":494},[484,1948,593],{"class":617},[484,1950,923],{"class":546},[484,1952,926],{"class":617},[484,1954,929],{"class":617},[484,1956,1957],{"class":486,"line":556},[484,1958,1631],{"class":1515},[484,1960,1961,1964,1966,1968,1970,1972,1974,1977],{"class":486,"line":562},[484,1962,1963],{"class":546},"    KStream",[484,1965,570],{"class":617},[484,1967,573],{"class":613},[484,1969,944],{"class":617},[484,1971,947],{"class":613},[484,1973,661],{"class":617},[484,1975,1976],{"class":967}," orders",[484,1978,1979],{"class":617}," =\n",[484,1981,1982,1985,1987,1989,1991,1993,1996,1998,2000,2002,2004,2006,2008,2010,2012,2014],{"class":486,"line":602},[484,1983,1984],{"class":967},"        builder",[484,1986,397],{"class":617},[484,1988,428],{"class":494},[484,1990,593],{"class":617},[484,1992,957],{"class":956},[484,1994,1995],{"class":583},"orders",[484,1997,957],{"class":956},[484,1999,944],{"class":617},[484,2001,968],{"class":967},[484,2003,397],{"class":617},[484,2005,973],{"class":494},[484,2007,593],{"class":617},[484,2009,957],{"class":956},[484,2011,980],{"class":583},[484,2013,957],{"class":956},[484,2015,2016],{"class":617},"));\n",[484,2018,2019],{"class":486,"line":641},[484,2020,534],{"emptyLinePlaceholder":533},[484,2022,2023],{"class":486,"line":680},[484,2024,1685],{"class":1515},[484,2026,2027],{"class":486,"line":690},[484,2028,1690],{"class":546},[484,2030,2031,2033,2035,2037,2039,2041,2044,2046,2048,2050,2052,2054,2056,2058,2060,2062,2064,2066,2068,2070,2072,2075,2077],{"class":486,"line":699},[484,2032,565],{"class":617},[484,2034,646],{"class":494},[484,2036,1035],{"class":617},[484,2038,1038],{"class":546},[484,2040,944],{"class":617},[484,2042,2043],{"class":546}," v",[484,2045,926],{"class":617},[484,2047,618],{"class":617},[484,2049,2043],{"class":967},[484,2051,397],{"class":617},[484,2053,1053],{"class":494},[484,2055,1056],{"class":617},[484,2057,1059],{"class":613},[484,2059,1709],{"class":664},[484,2061,944],{"class":617},[484,2063,1011],{"class":967},[484,2065,397],{"class":617},[484,2067,973],{"class":494},[484,2069,593],{"class":617},[484,2071,957],{"class":956},[484,2073,2074],{"class":583},"only-large",[484,2076,957],{"class":956},[484,2078,599],{"class":617},[484,2080,2081,2083,2085,2087,2089,2092,2094,2096,2099,2101,2103,2105,2107,2110,2112],{"class":486,"line":723},[484,2082,565],{"class":617},[484,2084,441],{"class":494},[484,2086,593],{"class":617},[484,2088,957],{"class":956},[484,2090,2091],{"class":583},"large-orders",[484,2093,957],{"class":956},[484,2095,944],{"class":617},[484,2097,2098],{"class":967}," Produced",[484,2100,397],{"class":617},[484,2102,973],{"class":494},[484,2104,593],{"class":617},[484,2106,957],{"class":956},[484,2108,2109],{"class":583},"large-sink",[484,2111,957],{"class":956},[484,2113,2016],{"class":617},[484,2115,2116],{"class":486,"line":740},[484,2117,534],{"emptyLinePlaceholder":533},[484,2119,2120],{"class":486,"line":755},[484,2121,1752],{"class":1515},[484,2123,2124],{"class":486,"line":761},[484,2125,1690],{"class":546},[484,2127,2128,2130,2132,2134,2137,2139,2141,2143,2145,2147,2149,2151,2153,2155,2157,2159,2161],{"class":486,"line":1759},[484,2129,565],{"class":617},[484,2131,607],{"class":494},[484,2133,593],{"class":617},[484,2135,2136],{"class":546},"v ",[484,2138,998],{"class":617},[484,2140,2043],{"class":967},[484,2142,397],{"class":617},[484,2144,1005],{"class":494},[484,2146,1008],{"class":617},[484,2148,1011],{"class":967},[484,2150,397],{"class":617},[484,2152,973],{"class":494},[484,2154,593],{"class":617},[484,2156,957],{"class":956},[484,2158,1022],{"class":583},[484,2160,957],{"class":956},[484,2162,599],{"class":617},[484,2164,2165,2167,2169,2171,2173,2176,2178,2180,2182,2184,2186,2188,2190,2193,2195],{"class":486,"line":1786},[484,2166,565],{"class":617},[484,2168,441],{"class":494},[484,2170,593],{"class":617},[484,2172,957],{"class":956},[484,2174,2175],{"class":583},"orders-upper",[484,2177,957],{"class":956},[484,2179,944],{"class":617},[484,2181,2098],{"class":967},[484,2183,397],{"class":617},[484,2185,973],{"class":494},[484,2187,593],{"class":617},[484,2189,957],{"class":956},[484,2191,2192],{"class":583},"upper-sink",[484,2194,957],{"class":956},[484,2196,2016],{"class":617},[484,2198,2199],{"class":486,"line":1809},[484,2200,764],{"class":617},[320,2202,2203,2204,2207,2208,2211,2212,2215,2216,2218,2219,2221,2222,2224],{},"The same rule applies to every topic-backed source: reuse the returned reference from ",[329,2205,2206],{},"table()"," and ",[329,2209,2210],{},"globalTable()"," rather than calling them twice for the same topic. ",[329,2213,2214],{},"scheduled()"," is ",[324,2217,1444],{}," topic-backed — each call defines its own independent source (there is no shared Kafka topic to conflict over), so two ",[329,2220,2214],{}," calls are never rejected. To branch a scheduled source's output, reuse its returned ",[329,2223,386],{}," reference the same way you would any other source.",[1169,2226,2228],{"color":1171,"icon":2227},"i-lucide-git-branch",[320,2229,2230,2231,2234,2235,2238,2239,2242,2243,2246,2247,2249,2250,2253,2254,397],{},"For ",[324,2232,2233],{},"first-match"," routing — where each record should go to exactly one of several mutually exclusive branches based on a predicate — use ",[329,2236,2237],{},"KStream.split()"," instead of manual fan-out. It returns a ",[329,2240,2241],{},"BranchedKStream"," and routes each record to the first matching branch (with an optional default). Manual fan-out (above) sends ",[1564,2244,2245],{},"every"," record down ",[1564,2248,2245],{}," branch; ",[329,2251,2252],{},"split()"," sends each record down ",[1564,2255,2256],{},"one",[416,2258,2260],{"id":2259},"where-to-go-next","Where to go next",[320,2262,2263],{},"Each operator family has a dedicated how-to:",[355,2265,2266,2276,2302,2318,2325,2332,2347,2354,2361,2372,2380],{},[358,2267,2268,2272,2273,2275],{},[324,2269,2270],{},[1195,2271,331],{"href":111}," — sources, sinks, global\u002Fread-only stores, and ",[329,2274,1210],{}," in depth.",[358,2277,2278,2283,2284,336,2287,336,2289,336,2292,336,2295,336,2298,2301],{},[324,2279,2280],{},[1195,2281,2282],{"href":116},"KStream and KTable"," — ",[329,2285,2286],{},"map",[329,2288,646],{},[329,2290,2291],{},"flatMap",[329,2293,2294],{},"selectKey",[329,2296,2297],{},"merge",[329,2299,2300],{},"split",", table operations, and stream↔table conversion.",[358,2303,2304,2283,2308,336,2311,336,2314,2317],{},[324,2305,2306],{},[1195,2307,120],{"href":121},[329,2309,2310],{},"count",[329,2312,2313],{},"reduce",[329,2315,2316],{},"aggregate",", grouping, and cogroup.",[358,2319,2320,2324],{},[324,2321,2322],{},[1195,2323,125],{"href":126}," — tumbling, hopping, sliding, and session windows.",[358,2326,2327,2331],{},[324,2328,2329],{},[1195,2330,130],{"href":131}," — stream-stream, stream-table, and table-table (incl. foreign-key) joins.",[358,2333,2334,2339,2340,370,2343,2346],{},[324,2335,2336],{},[1195,2337,2338],{"href":136},"Processor API"," — custom ",[329,2341,2342],{},"Processor",[329,2344,2345],{},"FixedKeyProcessor",", state-store access, timers, and punctuators.",[358,2348,2349,2353],{},[324,2350,2351],{},[1195,2352,140],{"href":141}," — interval- and cron-driven sources (a StoatFlow extension).",[358,2355,2356,2360],{},[324,2357,2358],{},[1195,2359,905],{"href":146}," — configuring serialization for keys and values.",[358,2362,2363,2367,2368,2371],{},[324,2364,2365],{},[1195,2366,100],{"href":101}," — store types, materialization, and the ",[329,2369,2370],{},"Materialized"," config.",[358,2373,2374,2379],{},[324,2375,2376],{},[1195,2377,2378],{"href":96},"Error handling & DLQ"," — deserialization and processing exception handlers.",[358,2381,2382,2387,2388,2391],{},[324,2383,2384],{},[1195,2385,2386],{"href":106},"Testing"," — the in-memory ",[329,2389,2390],{},"TopologyTestDriver",", no broker required.",[320,2393,2394,2395,397],{},"For the engine that runs the topology you build here — lanes, commit barriers, state durability — see ",[1195,2396,47],{"href":48},[2398,2399,2400],"style",{},"html pre.shiki code .sbBg2, html code.shiki .sbBg2{--shiki-default:#1E754F}html pre.shiki code .sySUi, html code.shiki .sySUi{--shiki-default:#59873A}html pre.shiki code .suHK_, html code.shiki .suHK_{--shiki-default:#393A34}html pre.shiki code .sUxyF, html code.shiki .sUxyF{--shiki-default:#2E8F82}html pre.shiki code .spphp, html code.shiki .spphp{--shiki-default:#B56959}html pre.shiki code .si04Y, html code.shiki .si04Y{--shiki-default:#AB5959}html pre.shiki code .sYZai, html code.shiki .sYZai{--shiki-default:#999999}html pre.shiki code .s-TwI, html code.shiki .s-TwI{--shiki-default:#2F798A}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sSP4y, html code.shiki .sSP4y{--shiki-default:#B5695977}html pre.shiki code .svycV, html code.shiki .svycV{--shiki-default:#B07D48}html pre.shiki code .s8zF2, html code.shiki .s8zF2{--shiki-default:#A0ADA0}",{"title":480,"searchDepth":498,"depth":498,"links":2402},[2403,2404,2405,2406],{"id":418,"depth":498,"text":419},{"id":1218,"depth":498,"text":1219},{"id":1425,"depth":498,"text":1426},{"id":2259,"depth":498,"text":2260},"How to define a StoatFlow topology — StreamsBuilder, the KStream\u002FKTable abstractions, and the fan-out rule that reuses a KStream reference for multiple branches.","md",{},{"icon":93},"how-to",{"title":92,"description":2407},"CdGFJ0hUZ7mN7Cm68-uyCypumN1d1iV6_zgtq4FmpGo",[2415,2417],{"title":82,"path":83,"stem":84,"description":2416,"icon":85,"children":-1},"The conceptual deltas if you already know Kafka Streams — single instance instead of a rebalancing cluster, in-memory re-keying instead of repartition topics, barrier-based exactly-once, global state, and lanes instead of partition-bound tasks. The DSL carries over unchanged.",{"title":95,"path":96,"stem":97,"description":2418,"icon":98,"children":-1},"Configure deserialization, processing, and production exception handlers — log-and-continue, log-and-fail, or dead-letter-queue — in code or YAML, and inspect the DLQ headers StoatFlow writes.",1783713352928]