[{"data":1,"prerenderedAt":1612},["ShallowReactive",2],{"navigation":3,"\u002Fdocs\u002Fconfiguration":314,"\u002Fdocs\u002Fconfiguration-surround":1607},[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":155,"body":316,"description":1600,"extension":1601,"meta":1602,"navigation":1603,"pageType":1604,"path":151,"seo":1605,"stem":152,"__hash__":1606},"docs\u002F1.docs\u002F4.configuration\u002F1.index.md",{"type":317,"value":318,"toc":1587},"minimark",[319,336,389,409,414,421,450,464,596,614,634,638,641,756,763,787,791,819,881,892,920,925,939,982,1006,1010,1019,1114,1133,1137,1149,1412,1421,1425,1430,1461,1490,1494,1501,1518,1525,1529,1583],[320,321,322,323,327,328,331,332,335],"p",{},"The ",[324,325,326],"code",{},":runtime"," module loads configuration from a layered set of sources: a bundled ",[324,329,330],{},"application.yaml",", external overlay files, environment variables, and JVM system properties — merged in a fixed precedence order. Non-serializable settings (serdes, exception handlers, callbacks) are supplied in code through a ",[324,333,334],{},"streamsConfigOverrides"," block. This page shows each source, the override forms, and the order in which they win.",[337,338,339],"tldr-panel",{},[340,341,342,361,371,380],"ul",{},[343,344,345,349,350,352,353,356,357,360],"li",{},[346,347,348],"strong",{},"Base config:"," ",[324,351,330],{}," (or ",[324,354,355],{},"application.yml",") on the classpath — usually ",[324,358,359],{},"src\u002Fmain\u002Fresources\u002F",".",[343,362,363,366,367,370],{},[346,364,365],{},"Overlay files:"," point ",[324,368,369],{},"STOATFLOW_CONFIG_FILES"," at one or more files; later files win, all must exist.",[343,372,373,349,376,379],{},[346,374,375],{},"Env vars:",[324,377,378],{},"STOATFLOW__LANES__COUNT=32"," — double underscore = dot, single underscore = word boundary (kebab-case).",[343,381,382,385,386,388],{},[346,383,384],{},"Order (highest wins):"," env vars → overlay files → classpath YAML → data-class defaults. Code ",[324,387,334],{}," always wins last.",[320,390,391,392,396,397,401,402,405,406,360],{},"For ",[393,394,395],"em",{},"why"," the model is layered this way — and how it maps onto the engine config versus the runtime infrastructure config — see ",[398,399,400],"a",{"href":73},"the configuration model",". For the actual keys, see ",[398,403,404],{"href":158},"core config"," and ",[398,407,408],{"href":163},"runtime config",[410,411,413],"h2",{"id":412},"the-config-tree","The config tree",[320,415,416,417,420],{},"All configuration lives under two top-level keys (plus an optional ",[324,418,419],{},"logging","):",[340,422,423,431,439],{},[343,424,425,430],{},[346,426,427],{},[324,428,429],{},"stoatflow:"," — the stream-processing engine: Kafka connection, lanes, commit barriers, state, changelog, watermarks, license.",[343,432,433,438],{},[346,434,435],{},[324,436,437],{},"runtime:"," — the runtime infrastructure: HTTP server, metrics, health checks, endpoint visibility.",[343,440,441,446,447,360],{},[346,442,443],{},[324,444,445],{},"logging:"," — per-logger levels, overriding ",[324,448,449],{},"logback.xml",[320,451,452,453,455,456,459,460,463],{},"A minimal ",[324,454,330],{}," only needs an ",[324,457,458],{},"application-id","; everything else has a default. Place it on the classpath at ",[324,461,462],{},"src\u002Fmain\u002Fresources\u002Fapplication.yaml",":",[465,466,471],"pre",{"className":467,"code":468,"language":469,"meta":470,"style":470},"language-yaml shiki shiki-themes vitesse-light","stoatflow:\n  application-id: word-count\n  bootstrap-servers: ${KAFKA_BOOTSTRAP_SERVERS:-localhost:9092}\n\n  license:\n    key: ${STOATFLOW_LICENSE_KEY}\n\nruntime:\n  http:\n    enabled: true\n    port: ${HTTP_PORT:-8080}\n  metrics:\n    enabled: true\n","yaml","",[324,472,473,486,498,509,516,524,535,540,548,556,568,579,587],{"__ignoreMap":470},[474,475,478,482],"span",{"class":476,"line":477},"line",1,[474,479,481],{"class":480},"su6XF","stoatflow",[474,483,485],{"class":484},"sYZai",":\n",[474,487,489,492,494],{"class":476,"line":488},2,[474,490,491],{"class":480},"  application-id",[474,493,463],{"class":484},[474,495,497],{"class":496},"spphp"," word-count\n",[474,499,501,504,506],{"class":476,"line":500},3,[474,502,503],{"class":480},"  bootstrap-servers",[474,505,463],{"class":484},[474,507,508],{"class":496}," ${KAFKA_BOOTSTRAP_SERVERS:-localhost:9092}\n",[474,510,512],{"class":476,"line":511},4,[474,513,515],{"emptyLinePlaceholder":514},true,"\n",[474,517,519,522],{"class":476,"line":518},5,[474,520,521],{"class":480},"  license",[474,523,485],{"class":484},[474,525,527,530,532],{"class":476,"line":526},6,[474,528,529],{"class":480},"    key",[474,531,463],{"class":484},[474,533,534],{"class":496}," ${STOATFLOW_LICENSE_KEY}\n",[474,536,538],{"class":476,"line":537},7,[474,539,515],{"emptyLinePlaceholder":514},[474,541,543,546],{"class":476,"line":542},8,[474,544,545],{"class":480},"runtime",[474,547,485],{"class":484},[474,549,551,554],{"class":476,"line":550},9,[474,552,553],{"class":480},"  http",[474,555,485],{"class":484},[474,557,559,562,564],{"class":476,"line":558},10,[474,560,561],{"class":480},"    enabled",[474,563,463],{"class":484},[474,565,567],{"class":566},"sbBg2"," true\n",[474,569,571,574,576],{"class":476,"line":570},11,[474,572,573],{"class":480},"    port",[474,575,463],{"class":484},[474,577,578],{"class":496}," ${HTTP_PORT:-8080}\n",[474,580,582,585],{"class":476,"line":581},12,[474,583,584],{"class":480},"  metrics",[474,586,485],{"class":484},[474,588,590,592,594],{"class":476,"line":589},13,[474,591,561],{"class":480},[474,593,463],{"class":484},[474,595,567],{"class":566},[597,598,601],"callout",{"color":599,"icon":600},"info","i-lucide-info",[320,602,603,405,606,609,610,613],{},[324,604,605],{},"${VAR}",[324,607,608],{},"${VAR:-default}"," are resolved by the config loader at startup — handy for keeping secrets and environment-specific values out of the committed YAML. This is the placeholder syntax, distinct from the env-var ",[393,611,612],{},"override"," mechanism described below.",[320,615,616,617,405,619,621,622,625,626,629,630,633],{},"The loader reads both ",[324,618,355],{},[324,620,330],{}," from the classpath if present; ",[324,623,624],{},".yml"," takes precedence over ",[324,627,628],{},".yaml"," when both exist. Both are optional — a config built entirely from environment variables and overlay files is valid as long as ",[324,631,632],{},"stoatflow.application-id"," resolves.",[410,635,637],{"id":636},"layered-precedence","Layered precedence",[320,639,640],{},"When the same key is set in more than one place, the highest-priority source wins. From highest to lowest:",[642,643,644,660],"table",{},[645,646,647],"thead",{},[648,649,650,654,657],"tr",{},[651,652,653],"th",{},"#",[651,655,656],{},"Source",[651,658,659],{},"Form",[661,662,663,680,697,713,729,742],"tbody",{},[648,664,665,669,676],{},[666,667,668],"td",{},"1",[666,670,671,672,675],{},"Environment variables, ",[324,673,674],{},"__"," path separator",[666,677,678],{},[324,679,378],{},[648,681,682,685,692],{},[666,683,684],{},"2",[666,686,687,688,691],{},"Environment variables, legacy ",[324,689,690],{},"STOATFLOW_"," prefix",[666,693,694],{},[324,695,696],{},"STOATFLOW_STOATFLOW_LANES_COUNT=32",[648,698,699,702,708],{},[666,700,701],{},"3",[666,703,704,705,707],{},"Overlay files from ",[324,706,369],{}," (later file wins)",[666,709,710],{},[324,711,712],{},"STOATFLOW_CONFIG_FILES=base.yaml,prod.yaml",[648,714,715,718,724],{},[666,716,717],{},"4",[666,719,720,721,723],{},"Bundled ",[324,722,355],{}," on the classpath",[666,725,726],{},[324,727,728],{},"src\u002Fmain\u002Fresources\u002Fapplication.yml",[648,730,731,734,738],{},[666,732,733],{},"5",[666,735,720,736,723],{},[324,737,330],{},[666,739,740],{},[324,741,462],{},[648,743,744,747,750],{},[666,745,746],{},"6",[666,748,749],{},"Default values in the config data classes",[666,751,752,753],{},"e.g. ",[324,754,755],{},"runtime.http.port = 8080",[320,757,758,759,762],{},"This is the order applied by the config loader (",[324,760,761],{},"ConfigLoader.kt","). The two env-var conventions in rows 1-2 are layered together as the highest-priority sources, ahead of files.",[597,764,765],{"color":599,"icon":600},[320,766,767,770,771,774,775,778,779,782,783,786],{},[346,768,769],{},"System properties."," A handful of settings — notably the ",[398,772,773],{"href":24},"license"," — are read as JVM system properties (",[324,776,777],{},"-Dstoatflow.license.key=...","). For the license specifically, env vars and ",[324,780,781],{},"-D"," system properties take precedence over the YAML ",[324,784,785],{},"stoatflow.license.*"," fields. System properties are not a general override layer for the whole config tree; use environment variables or overlay files for that.",[410,788,790],{"id":789},"environment-variables","Environment variables",[320,792,793,794,799,800,807,808,811,812,815,816,463],{},"The recommended convention uses ",[346,795,796,798],{},[324,797,674],{}," (double underscore) as the path separator"," and a ",[346,801,802,803,806],{},"single ",[324,804,805],{},"_"," as a word boundary"," within a property name (converted to kebab-case). The first segment must be a top-level key — ",[324,809,810],{},"STOATFLOW",", ",[324,813,814],{},"RUNTIME",", or ",[324,817,818],{},"LOGGING",[465,820,824],{"className":821,"code":822,"language":823,"meta":470,"style":470},"language-bash shiki shiki-themes vitesse-light","STOATFLOW__LANES__COUNT=32                                    # stoatflow.lanes.count\nSTOATFLOW__COMMIT_BARRIER__INTERVAL_MS=5000                   # stoatflow.commit-barrier.interval-ms\nSTOATFLOW__VALIDATION__PRE_FLIGHT_CONSUMER_GROUP_CHECK=false  # stoatflow.validation.pre-flight-consumer-group-check\nRUNTIME__HTTP__PORT=9090                                      # runtime.http.port\n","bash",[324,825,826,842,855,868],{"__ignoreMap":470},[474,827,828,832,835,838],{"class":476,"line":477},[474,829,831],{"class":830},"svycV","STOATFLOW__LANES__COUNT",[474,833,834],{"class":484},"=",[474,836,837],{"class":496},"32",[474,839,841],{"class":840},"s8zF2","                                    # stoatflow.lanes.count\n",[474,843,844,847,849,852],{"class":476,"line":488},[474,845,846],{"class":830},"STOATFLOW__COMMIT_BARRIER__INTERVAL_MS",[474,848,834],{"class":484},[474,850,851],{"class":496},"5000",[474,853,854],{"class":840},"                   # stoatflow.commit-barrier.interval-ms\n",[474,856,857,860,862,865],{"class":476,"line":500},[474,858,859],{"class":830},"STOATFLOW__VALIDATION__PRE_FLIGHT_CONSUMER_GROUP_CHECK",[474,861,834],{"class":484},[474,863,864],{"class":496},"false",[474,866,867],{"class":840},"  # stoatflow.validation.pre-flight-consumer-group-check\n",[474,869,870,873,875,878],{"class":476,"line":511},[474,871,872],{"class":830},"RUNTIME__HTTP__PORT",[474,874,834],{"class":484},[474,876,877],{"class":496},"9090",[474,879,880],{"class":840},"                                      # runtime.http.port\n",[320,882,883,884,887,888,891],{},"The double-underscore form is the one to use because it can express multi-word property names (",[324,885,886],{},"pre-flight-consumer-group-check","). The convention matches Docker Compose and Quarkus (",[324,889,890],{},"RelaxedEnvironmentPropertySource.kt",").",[597,893,895],{"color":894,"icon":80},"warning",[320,896,897,903,904,811,906,909,910,913,914,916,917,919],{},[346,898,899,900,902],{},"Legacy ",[324,901,690],{}," prefix."," A single-underscore form (",[324,905,696],{},[324,907,908],{},"STOATFLOW_RUNTIME_HTTP_PORT=9090",") also works but ",[346,911,912],{},"cannot set multi-word property names"," because it uses ",[324,915,805],{}," as both separators. Prefer the ",[324,918,674],{}," form for anything new.",[921,922,924],"h3",{"id":923},"kafka-client-and-logging-maps","Kafka client and logging maps",[320,926,927,928,931,932,811,935,938],{},"Kafka client properties and logging levels are ",[324,929,930],{},"Map\u003CString, String>"," entries whose keys must keep their dots and word boundaries (",[324,933,934],{},"linger.ms",[324,936,937],{},"org.apache.kafka.clients","). Those are read directly from the environment with their own conventions:",[465,940,942],{"className":821,"code":941,"language":823,"meta":470,"style":470},"STOATFLOW__KAFKA__PRODUCER__LINGER_MS=5                       # producer linger.ms = 5\nSTOATFLOW__KAFKA__CONSUMER__MAX_POLL_RECORDS=1000            # consumer max.poll.records = 1000\nLOGGING__LEVEL__ORG_APACHE_KAFKA_CLIENTS=DEBUG               # org.apache.kafka.clients = DEBUG\n",[324,943,944,956,969],{"__ignoreMap":470},[474,945,946,949,951,953],{"class":476,"line":477},[474,947,948],{"class":830},"STOATFLOW__KAFKA__PRODUCER__LINGER_MS",[474,950,834],{"class":484},[474,952,733],{"class":496},[474,954,955],{"class":840},"                       # producer linger.ms = 5\n",[474,957,958,961,963,966],{"class":476,"line":488},[474,959,960],{"class":830},"STOATFLOW__KAFKA__CONSUMER__MAX_POLL_RECORDS",[474,962,834],{"class":484},[474,964,965],{"class":496},"1000",[474,967,968],{"class":840},"            # consumer max.poll.records = 1000\n",[474,970,971,974,976,979],{"class":476,"line":500},[474,972,973],{"class":830},"LOGGING__LEVEL__ORG_APACHE_KAFKA_CLIENTS",[474,975,834],{"class":484},[474,977,978],{"class":496},"DEBUG",[474,980,981],{"class":840},"               # org.apache.kafka.clients = DEBUG\n",[320,983,984,985,987,988,990,991,994,995,997,998,1001,1002,1005],{},"Inside these segments, ",[324,986,805],{}," becomes ",[324,989,360],{}," — so ",[324,992,993],{},"LINGER_MS"," resolves to ",[324,996,934],{}," and env-var entries take precedence over the same key set in YAML (",[324,999,1000],{},"ConfigMapper.kt","). See ",[398,1003,1004],{"href":173},"Kafka client config"," for the full surface.",[410,1007,1009],{"id":1008},"overlay-files","Overlay files",[320,1011,1012,1013,1015,1016,463],{},"For deployment-specific configuration that you don't want baked into the application JAR, set ",[324,1014,369],{}," to a comma-separated list of file paths. The files are deep-merged on top of the bundled classpath YAML, and ",[346,1017,1018],{},"later files in the list override earlier ones",[465,1020,1022],{"className":821,"code":1021,"language":823,"meta":470,"style":470},"# Single external file\nexport STOATFLOW_CONFIG_FILES=\u002Fetc\u002Fmyapp\u002Fapplication.yaml\n\n# Multiple files — last wins\nexport STOATFLOW_CONFIG_FILES=\u002Fetc\u002Fmyapp\u002Fbase.yaml,\u002Fetc\u002Fmyapp\u002Fprod-overrides.yaml\n",[324,1023,1024,1029,1062,1066,1071],{"__ignoreMap":470},[474,1025,1026],{"class":476,"line":477},[474,1027,1028],{"class":840},"# Single external file\n",[474,1030,1031,1035,1038,1040,1044,1047,1049,1052,1054,1057,1059],{"class":476,"line":488},[474,1032,1034],{"class":1033},"si04Y","export",[474,1036,1037],{"class":830}," STOATFLOW_CONFIG_FILES",[474,1039,834],{"class":484},[474,1041,1043],{"class":1042},"suHK_","\u002F",[474,1045,1046],{"class":830},"etc",[474,1048,1043],{"class":1042},[474,1050,1051],{"class":830},"myapp",[474,1053,1043],{"class":1042},[474,1055,1056],{"class":830},"application",[474,1058,360],{"class":1042},[474,1060,1061],{"class":830},"yaml\n",[474,1063,1064],{"class":476,"line":500},[474,1065,515],{"emptyLinePlaceholder":514},[474,1067,1068],{"class":476,"line":511},[474,1069,1070],{"class":840},"# Multiple files — last wins\n",[474,1072,1073,1075,1077,1079,1081,1083,1085,1087,1089,1092,1094,1096,1099,1101,1103,1105,1107,1110,1112],{"class":476,"line":518},[474,1074,1034],{"class":1033},[474,1076,1037],{"class":830},[474,1078,834],{"class":484},[474,1080,1043],{"class":1042},[474,1082,1046],{"class":830},[474,1084,1043],{"class":1042},[474,1086,1051],{"class":830},[474,1088,1043],{"class":1042},[474,1090,1091],{"class":830},"base",[474,1093,360],{"class":1042},[474,1095,469],{"class":830},[474,1097,1098],{"class":1042},",\u002F",[474,1100,1046],{"class":830},[474,1102,1043],{"class":1042},[474,1104,1051],{"class":830},[474,1106,1043],{"class":1042},[474,1108,1109],{"class":830},"prod-overrides",[474,1111,360],{"class":1042},[474,1113,1061],{"class":830},[320,1115,1116,1117,405,1119,1121,1122,1125,1126,1128,1129,1132],{},"Supported extensions are ",[324,1118,628],{},[324,1120,624],{},". Every file listed is ",[346,1123,1124],{},"mandatory"," — if any path doesn't exist (or isn't a regular file) the runtime fails to start with a clear error naming the missing path (",[324,1127,761],{},"). This is the recommended way to inject a Kubernetes ",[324,1130,1131],{},"ConfigMap"," or a mounted secrets file into the runtime.",[410,1134,1136],{"id":1135},"programmatic-overrides","Programmatic overrides",[320,1138,1139,1140,1142,1143,1146,1147,420],{},"YAML and environment variables cover everything that can be expressed as a string, a number, or a class name. Things that can't — live serde instances, exception-handler objects, callbacks — are configured in code through the ",[324,1141,334],{}," block on the runtime builder. These overrides are applied ",[346,1144,1145],{},"last",", taking precedence over every YAML and env-var source (",[324,1148,1000],{},[1150,1151,1153,1274],"code-tabs",{"group":1152},"lang",[465,1154,1159],{"className":1155,"code":1156,"filename":1157,"language":1158,"meta":470,"style":470},"language-kotlin shiki shiki-themes vitesse-light","val runtime = StoatFlowRuntime.fromConfig(\n    topologyBuilder = { buildTopology(it) },\n    configure = {\n        streamsConfigOverrides {\n            defaultKeySerde(Serdes.String())\n            defaultValueSerde(Serdes.String())\n        }\n    },\n)\nruntime.start()\nruntime.awaitTermination()\n","Kotlin","kotlin",[324,1160,1161,1181,1197,1207,1214,1228,1239,1244,1249,1254,1265],{"__ignoreMap":470},[474,1162,1163,1166,1169,1171,1174,1178],{"class":476,"line":477},[474,1164,1165],{"class":566},"val",[474,1167,1168],{"class":1042}," runtime ",[474,1170,834],{"class":484},[474,1172,1173],{"class":1042}," StoatFlowRuntime.",[474,1175,1177],{"class":1176},"sySUi","fromConfig",[474,1179,1180],{"class":1042},"(\n",[474,1182,1183,1186,1188,1191,1194],{"class":476,"line":488},[474,1184,1185],{"class":1042},"    topologyBuilder ",[474,1187,834],{"class":484},[474,1189,1190],{"class":1042}," { ",[474,1192,1193],{"class":1176},"buildTopology",[474,1195,1196],{"class":1042},"(it) },\n",[474,1198,1199,1202,1204],{"class":476,"line":500},[474,1200,1201],{"class":1042},"    configure ",[474,1203,834],{"class":484},[474,1205,1206],{"class":1042}," {\n",[474,1208,1209,1212],{"class":476,"line":511},[474,1210,1211],{"class":1176},"        streamsConfigOverrides",[474,1213,1206],{"class":1042},[474,1215,1216,1219,1222,1225],{"class":476,"line":518},[474,1217,1218],{"class":1176},"            defaultKeySerde",[474,1220,1221],{"class":1042},"(Serdes.",[474,1223,1224],{"class":1176},"String",[474,1226,1227],{"class":1042},"())\n",[474,1229,1230,1233,1235,1237],{"class":476,"line":526},[474,1231,1232],{"class":1176},"            defaultValueSerde",[474,1234,1221],{"class":1042},[474,1236,1224],{"class":1176},[474,1238,1227],{"class":1042},[474,1240,1241],{"class":476,"line":537},[474,1242,1243],{"class":1042},"        }\n",[474,1245,1246],{"class":476,"line":542},[474,1247,1248],{"class":1042},"    },\n",[474,1250,1251],{"class":476,"line":550},[474,1252,1253],{"class":1042},")\n",[474,1255,1256,1259,1262],{"class":476,"line":558},[474,1257,1258],{"class":1042},"runtime.",[474,1260,1261],{"class":1176},"start",[474,1263,1264],{"class":1042},"()\n",[474,1266,1267,1269,1272],{"class":476,"line":570},[474,1268,1258],{"class":1042},[474,1270,1271],{"class":1176},"awaitTermination",[474,1273,1264],{"class":1042},[465,1275,1280],{"className":1276,"code":1277,"filename":1278,"language":1279,"meta":470,"style":470},"language-java shiki shiki-themes vitesse-light","var runtime = StoatFlowRuntime.fromConfig(\n    Main::buildTopology,\n    builder -> builder.streamsConfigOverrides(cfg -> {\n        cfg.defaultKeySerde(Serdes.String());\n        cfg.defaultValueSerde(Serdes.String());\n    })\n);\nruntime.start();\nruntime.awaitTermination();\n","Java","java",[324,1281,1282,1302,1315,1340,1362,1381,1386,1391,1402],{"__ignoreMap":470},[474,1283,1284,1287,1290,1293,1296,1298,1300],{"class":476,"line":477},[474,1285,1286],{"class":1033},"var",[474,1288,1289],{"class":830}," runtime",[474,1291,1292],{"class":484}," =",[474,1294,1295],{"class":830}," StoatFlowRuntime",[474,1297,360],{"class":484},[474,1299,1177],{"class":1176},[474,1301,1180],{"class":484},[474,1303,1304,1307,1310,1312],{"class":476,"line":488},[474,1305,1306],{"class":1042},"    Main",[474,1308,1309],{"class":566},"::",[474,1311,1193],{"class":1042},[474,1313,1314],{"class":484},",\n",[474,1316,1317,1320,1323,1326,1328,1330,1333,1336,1338],{"class":476,"line":500},[474,1318,1319],{"class":1042},"    builder ",[474,1321,1322],{"class":484},"->",[474,1324,1325],{"class":830}," builder",[474,1327,360],{"class":484},[474,1329,334],{"class":1176},[474,1331,1332],{"class":484},"(",[474,1334,1335],{"class":1042},"cfg ",[474,1337,1322],{"class":484},[474,1339,1206],{"class":484},[474,1341,1342,1345,1347,1350,1352,1355,1357,1359],{"class":476,"line":511},[474,1343,1344],{"class":830},"        cfg",[474,1346,360],{"class":484},[474,1348,1349],{"class":1176},"defaultKeySerde",[474,1351,1332],{"class":484},[474,1353,1354],{"class":830},"Serdes",[474,1356,360],{"class":484},[474,1358,1224],{"class":1176},[474,1360,1361],{"class":484},"());\n",[474,1363,1364,1366,1368,1371,1373,1375,1377,1379],{"class":476,"line":518},[474,1365,1344],{"class":830},[474,1367,360],{"class":484},[474,1369,1370],{"class":1176},"defaultValueSerde",[474,1372,1332],{"class":484},[474,1374,1354],{"class":830},[474,1376,360],{"class":484},[474,1378,1224],{"class":1176},[474,1380,1361],{"class":484},[474,1382,1383],{"class":476,"line":526},[474,1384,1385],{"class":484},"    })\n",[474,1387,1388],{"class":476,"line":537},[474,1389,1390],{"class":484},");\n",[474,1392,1393,1395,1397,1399],{"class":476,"line":542},[474,1394,545],{"class":830},[474,1396,360],{"class":484},[474,1398,1261],{"class":1176},[474,1400,1401],{"class":484},"();\n",[474,1403,1404,1406,1408,1410],{"class":476,"line":550},[474,1405,545],{"class":830},[474,1407,360],{"class":484},[474,1409,1271],{"class":1176},[474,1411,1401],{"class":484},[320,1413,1414,1416,1417,1420],{},[324,1415,334],{}," exposes the same ",[324,1418,1419],{},"StreamsConfig.Builder"," the YAML mapping populates — so anything you can set in YAML you can also set here, and your code wins. Reserve it for the non-serializable types and for values you'd rather compute at runtime than declare statically.",[921,1422,1424],{"id":1423},"class-name-configuration-in-yaml","Class-name configuration in YAML",[320,1426,1427,1428,463],{},"Some non-serializable types have a middle ground: if the class has a no-arg constructor, you can name it in YAML as a fully qualified class name and the runtime instantiates it for you. These are applied above the YAML defaults but below ",[324,1429,334],{},[465,1431,1433],{"className":467,"code":1432,"language":469,"meta":470,"style":470},"stoatflow:\n  default-key-serde: org.apache.kafka.common.serialization.Serdes$StringSerde\n  deserialization-exception-handler: io.stoatflow.core.exception.LogAndContinueDeserializationExceptionHandler\n",[324,1434,1435,1441,1451],{"__ignoreMap":470},[474,1436,1437,1439],{"class":476,"line":477},[474,1438,481],{"class":480},[474,1440,485],{"class":484},[474,1442,1443,1446,1448],{"class":476,"line":488},[474,1444,1445],{"class":480},"  default-key-serde",[474,1447,463],{"class":484},[474,1449,1450],{"class":496}," org.apache.kafka.common.serialization.Serdes$StringSerde\n",[474,1452,1453,1456,1458],{"class":476,"line":500},[474,1454,1455],{"class":480},"  deserialization-exception-handler",[474,1457,463],{"class":484},[474,1459,1460],{"class":496}," io.stoatflow.core.exception.LogAndContinueDeserializationExceptionHandler\n",[320,1462,1463,1464,811,1467,811,1470,811,1473,811,1476,1479,1480,1483,1484,1486,1487,1489],{},"The supported class-name keys are ",[324,1465,1466],{},"default-key-serde",[324,1468,1469],{},"default-value-serde",[324,1471,1472],{},"deserialization-exception-handler",[324,1474,1475],{},"production-exception-handler",[324,1477,1478],{},"processing-exception-handler",", and ",[324,1481,1482],{},"rocks-db-config-setter"," (",[324,1485,1000],{},"). Anything requiring a constructor argument must go through ",[324,1488,334],{}," instead.",[410,1491,1493],{"id":1492},"inspecting-the-merged-result","Inspecting the merged result",[320,1495,1496,1497,1500],{},"The runtime exposes the fully merged, masked configuration at the ",[324,1498,1499],{},"\u002Fconfig"," HTTP endpoint — useful for confirming that an env-var override or overlay file actually landed where you expected. Sensitive values (passwords, secrets, tokens) are masked in the output:",[465,1502,1504],{"className":821,"code":1503,"language":823,"meta":470,"style":470},"curl -s localhost:8080\u002Fconfig\n",[324,1505,1506],{"__ignoreMap":470},[474,1507,1508,1511,1515],{"class":476,"line":477},[474,1509,1510],{"class":1176},"curl",[474,1512,1514],{"class":1513},"sEi1f"," -s",[474,1516,1517],{"class":496}," localhost:8080\u002Fconfig\n",[320,1519,1520,1521,1524],{},"See the ",[398,1522,1523],{"href":186},"REST API"," for the full endpoint reference.",[410,1526,1528],{"id":1527},"next-steps","Next steps",[340,1530,1531,1545,1557,1568,1576],{},[343,1532,1533,1538,1539,1541,1542,1544],{},[346,1534,1535],{},[398,1536,1537],{"href":73},"Configuration model"," — why config is split into ",[324,1540,481],{}," (engine) and ",[324,1543,545],{}," (infrastructure), and how it composes.",[343,1546,1547,1552,1553,1556],{},[346,1548,1549],{},[398,1550,1551],{"href":158},"Core config"," — the ",[324,1554,1555],{},"stoatflow.*"," keys: lanes, barriers, state, changelog, watermarks.",[343,1558,1559,1552,1564,1567],{},[346,1560,1561],{},[398,1562,1563],{"href":163},"Runtime config",[324,1565,1566],{},"runtime.*"," keys: HTTP server, metrics, health, endpoints.",[343,1569,1570,1575],{},[346,1571,1572],{},[398,1573,1574],{"href":168},"Defaults and presets"," — what the out-of-the-box defaults are and the RocksDB presets.",[343,1577,1578,1582],{},[346,1579,1580],{},[398,1581,281],{"href":282}," — every key in one table.",[1584,1585,1586],"style",{},"html pre.shiki code .su6XF, html code.shiki .su6XF{--shiki-default:#998418}html pre.shiki code .sYZai, html code.shiki .sYZai{--shiki-default:#999999}html pre.shiki code .spphp, html code.shiki .spphp{--shiki-default:#B56959}html pre.shiki code .sbBg2, html code.shiki .sbBg2{--shiki-default:#1E754F}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 .svycV, html code.shiki .svycV{--shiki-default:#B07D48}html pre.shiki code .s8zF2, html code.shiki .s8zF2{--shiki-default:#A0ADA0}html pre.shiki code .si04Y, html code.shiki .si04Y{--shiki-default:#AB5959}html pre.shiki code .suHK_, html code.shiki .suHK_{--shiki-default:#393A34}html pre.shiki code .sySUi, html code.shiki .sySUi{--shiki-default:#59873A}html pre.shiki code .sEi1f, html code.shiki .sEi1f{--shiki-default:#A65E2B}",{"title":470,"searchDepth":488,"depth":488,"links":1588},[1589,1590,1591,1594,1595,1598,1599],{"id":412,"depth":488,"text":413},{"id":636,"depth":488,"text":637},{"id":789,"depth":488,"text":790,"children":1592},[1593],{"id":923,"depth":500,"text":924},{"id":1008,"depth":488,"text":1009},{"id":1135,"depth":488,"text":1136,"children":1596},[1597],{"id":1423,"depth":500,"text":1424},{"id":1492,"depth":488,"text":1493},{"id":1527,"depth":488,"text":1528},"How the StoatFlow runtime loads configuration — application.yaml on the classpath, overlay files, environment variables, system properties, and the layered precedence order.","md",{},{"icon":75},"how-to",{"title":155,"description":1600},"x-x1NlIdMzIC8RiDA_S1vhyaILShIno1G8z67aBss6E",[1608,1610],{"title":145,"path":146,"stem":147,"description":1609,"icon":148,"children":-1},"Configure default and per-operator serdes, use the built-in Serdes, write custom serdes, serialize windowed keys, and wire up Avro with Confluent Schema Registry.",{"title":157,"path":158,"stem":159,"description":1611,"icon":160,"children":-1},"The :core engine knobs every StoatFlow app sets — application id, brokers, default serdes, lanes, commit-barrier cadence, state dir, changelog, processing guarantee, and event-time coordination — with defaults from source.",1783713353196]