[{"data":1,"prerenderedAt":1738},["ShallowReactive",2],{"navigation":3,"\u002Fdocs\u002Fconfiguration\u002Fdefaults-and-presets":314,"\u002Fdocs\u002Fconfiguration\u002Fdefaults-and-presets-surround":1733},[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":167,"body":316,"description":1726,"extension":1727,"meta":1728,"navigation":1729,"pageType":1730,"path":168,"seo":1731,"stem":169,"__hash__":1732},"docs\u002F1.docs\u002F4.configuration\u002F4.defaults-and-presets.md",{"type":317,"value":318,"toc":1712},"minimark",[319,337,384,389,396,442,448,560,563,704,714,718,737,742,745,846,901,912,916,923,1023,1086,1096,1103,1158,1178,1182,1185,1264,1268,1275,1279,1323,1388,1395,1399,1434,1438,1441,1665,1682,1686,1708],[320,321,322,323,327,328,332,333,336],"p",{},"StoatFlow ships opinionated defaults so a near-empty ",[324,325,326],"code",{},"application.yaml"," runs a correct, bounded-memory application out of the box. This page explains what those defaults give you, which behaviour adapts at runtime versus what you set explicitly, and the RocksDB presets and bound knobs available when you do need to tune. For the layered resolution rules behind these settings (env \u002F system property \u002F YAML \u002F programmatic precedence), see ",[329,330,331],"a",{"href":73},"Configuration model","; for a workload-driven walkthrough, see ",[329,334,335],{"href":249},"Tuning",".",[338,339,340],"tldr-panel",{},[341,342,343,355,361,367],"ul",{},[344,345,346,350,351,354],"li",{},[347,348,349],"strong",{},"Minimal config works"," — only ",[324,352,353],{},"application-id"," is required; every other key has a sensible default.",[344,356,357,360],{},[347,358,359],{},"Bounded by default"," — RocksDB memory, uncommitted state, and lane queues all have caps out of the box, unlike Kafka Streams' unbounded defaults.",[344,362,363,366],{},[347,364,365],{},"Commit cadence and epoch size self-tune"," within the interval and memory bounds you set — you configure the envelope, the runtime adapts inside it.",[344,368,369,372,373,376,377,376,380,383],{},[347,370,371],{},"RocksDB has three presets"," (",[324,374,375],{},"DEFAULT",", ",[324,378,379],{},"LOW_MEMORY",[324,381,382],{},"HIGH_PERFORMANCE",") plus a config-setter escape hatch for full control.",[385,386,388],"h2",{"id":387},"a-minimal-config-that-works","A minimal config that works",[320,390,391,392,395],{},"The only required key is ",[324,393,394],{},"stoatflow.application-id",". Everything else falls back to a default. A complete, runnable configuration can be as short as this:",[397,398,403],"pre",{"className":399,"code":400,"language":401,"meta":402,"style":402},"language-yaml shiki shiki-themes vitesse-light","stoatflow:\n  application-id: my-app\n  bootstrap-servers: localhost:9092\n","yaml","",[324,404,405,418,431],{"__ignoreMap":402},[406,407,410,414],"span",{"class":408,"line":409},"line",1,[406,411,413],{"class":412},"su6XF","stoatflow",[406,415,417],{"class":416},"sYZai",":\n",[406,419,421,424,427],{"class":408,"line":420},2,[406,422,423],{"class":412},"  application-id",[406,425,426],{"class":416},":",[406,428,430],{"class":429},"spphp"," my-app\n",[406,432,434,437,439],{"class":408,"line":433},3,[406,435,436],{"class":412},"  bootstrap-servers",[406,438,426],{"class":416},[406,440,441],{"class":429}," localhost:9092\n",[320,443,444,445,447],{},"Add the runtime's HTTP and metrics endpoints and the license, and you have what ",[329,446,28],{"href":29}," uses:",[397,449,451],{"className":399,"code":450,"language":401,"meta":402,"style":402},"stoatflow:\n  application-id: word-count\n  bootstrap-servers: ${KAFKA_BOOTSTRAP_SERVERS:-localhost:9092}\n  license:\n    key: ${STOATFLOW_LICENSE_KEY}\n\nruntime:\n  http:\n    enabled: true\n    port: 8080\n  metrics:\n    enabled: true\n",[324,452,453,459,468,477,485,496,503,511,519,531,543,551],{"__ignoreMap":402},[406,454,455,457],{"class":408,"line":409},[406,456,413],{"class":412},[406,458,417],{"class":416},[406,460,461,463,465],{"class":408,"line":420},[406,462,423],{"class":412},[406,464,426],{"class":416},[406,466,467],{"class":429}," word-count\n",[406,469,470,472,474],{"class":408,"line":433},[406,471,436],{"class":412},[406,473,426],{"class":416},[406,475,476],{"class":429}," ${KAFKA_BOOTSTRAP_SERVERS:-localhost:9092}\n",[406,478,480,483],{"class":408,"line":479},4,[406,481,482],{"class":412},"  license",[406,484,417],{"class":416},[406,486,488,491,493],{"class":408,"line":487},5,[406,489,490],{"class":412},"    key",[406,492,426],{"class":416},[406,494,495],{"class":429}," ${STOATFLOW_LICENSE_KEY}\n",[406,497,499],{"class":408,"line":498},6,[406,500,502],{"emptyLinePlaceholder":501},true,"\n",[406,504,506,509],{"class":408,"line":505},7,[406,507,508],{"class":412},"runtime",[406,510,417],{"class":416},[406,512,514,517],{"class":408,"line":513},8,[406,515,516],{"class":412},"  http",[406,518,417],{"class":416},[406,520,522,525,527],{"class":408,"line":521},9,[406,523,524],{"class":412},"    enabled",[406,526,426],{"class":416},[406,528,530],{"class":529},"sbBg2"," true\n",[406,532,534,537,539],{"class":408,"line":533},10,[406,535,536],{"class":412},"    port",[406,538,426],{"class":416},[406,540,542],{"class":541},"s-TwI"," 8080\n",[406,544,546,549],{"class":408,"line":545},11,[406,547,548],{"class":412},"  metrics",[406,550,417],{"class":416},[406,552,554,556,558],{"class":408,"line":553},12,[406,555,524],{"class":412},[406,557,426],{"class":416},[406,559,530],{"class":529},[320,561,562],{},"This runs because the defaults already make the right choices for most workloads. The ones worth knowing:",[564,565,566,582],"table",{},[567,568,569],"thead",{},[570,571,572,576,579],"tr",{},[573,574,575],"th",{},"Concern",[573,577,578],{},"Default",[573,580,581],{},"Why",[583,584,585,599,612,625,636,647,661,672,683],"tbody",{},[570,586,587,591,596],{},[588,589,590],"td",{},"Processing guarantee",[588,592,593],{},[324,594,595],{},"EXACTLY_ONCE",[588,597,598],{},"Atomic commit of output, changelog, and offsets in one Kafka transaction.",[570,600,601,604,609],{},[588,602,603],{},"Lane count",[588,605,606],{},[324,607,608],{},"max(2, CPU cores)",[588,610,611],{},"Parallelism scales with the machine you run on.",[570,613,614,617,622],{},[588,615,616],{},"Lane queue capacity",[588,618,619],{},[324,620,621],{},"300",[588,623,624],{},"Per-lane backpressure bound.",[570,626,627,630,633],{},[588,628,629],{},"State store backend",[588,631,632],{},"RocksDB (FFM)",[588,634,635],{},"Persistent, on-disk, no virtual-thread pinning.",[570,637,638,641,644],{},[588,639,640],{},"RocksDB memory",[588,642,643],{},"~256 MB total",[588,645,646],{},"Bounded by default — Kafka Streams is unbounded.",[570,648,649,652,655],{},[588,650,651],{},"Changelog topics",[588,653,654],{},"enabled, auto-created",[588,656,657,658,336],{},"State survives restart; topics created with ",[324,659,660],{},"cleanup.policy=compact",[570,662,663,666,669],{},[588,664,665],{},"Explicit naming",[588,667,668],{},"enforced",[588,670,671],{},"Every operator and store needs a stable name (KIP-1111); fails fast otherwise.",[570,673,674,677,680],{},[588,675,676],{},"State restoration",[588,678,679],{},"enabled",[588,681,682],{},"Local state rebuilds from changelog on cold start.",[570,684,685,688,693],{},[588,686,687],{},"Default serdes",[588,689,690],{},[324,691,692],{},"ByteArray",[588,694,695,696,699,700,703],{},"Set ",[324,697,698],{},"default-key-serde"," \u002F ",[324,701,702],{},"default-value-serde"," (or per-operator serdes) for real types.",[705,706,708],"callout",{"color":707,"icon":55},"info",[320,709,710,713],{},[347,711,712],{},"Bounded by default is the deliberate difference from Kafka Streams."," RocksDB memory (~256 MB), total uncommitted state (256 MB), and lane queue depth (300) all have caps without you setting anything. The goal is that the default config does not OOM a modestly sized container under load — you raise the caps when you have headroom, rather than discovering an unbounded default the hard way.",[385,715,717],{"id":716},"what-adapts-and-what-you-set","What adapts, and what you set",[320,719,720,721,724,725,728,729,733,734,336],{},"Some runtime behaviour is ",[347,722,723],{},"adaptive",": the engine measures its own commit cost and state-write rate and adjusts within bounds. The rest is ",[347,726,727],{},"fixed"," to what you configure. The split matters because you tune the two kinds differently — for adaptive behaviour you set the ",[730,731,732],"em",{},"envelope",", for fixed behaviour you set the ",[730,735,736],{},"value",[738,739,741],"h3",{"id":740},"commit-cadence-self-tunes-within-an-interval-band","Commit cadence self-tunes within an interval band",[320,743,744],{},"The commit barrier interval is not a fixed sleep. The runtime estimates how long a commit takes and schedules the next barrier relative to that estimate, so a topology with fast commits barriers more often and a topology with slow commits backs off — both staying inside the band you configure. You set the band; the runtime picks the cadence inside it.",[564,746,747,759],{},[567,748,749],{},[570,750,751,754,756],{},[573,752,753],{},"YAML key",[573,755,578],{},[573,757,758],{},"What it sets",[583,760,761,776,791,806,821],{},[570,762,763,768,773],{},[588,764,765],{},[324,766,767],{},"commit-barrier.interval-ms",[588,769,770],{},[324,771,772],{},"500",[588,774,775],{},"Seed interval used before the runtime has measured a commit.",[570,777,778,783,788],{},[588,779,780],{},[324,781,782],{},"commit-barrier.min-interval-ms",[588,784,785],{},[324,786,787],{},"150",[588,789,790],{},"Floor — barriers never fire closer together than this.",[570,792,793,798,803],{},[588,794,795],{},[324,796,797],{},"commit-barrier.max-interval-ms",[588,799,800],{},[324,801,802],{},"5000",[588,804,805],{},"Ceiling — barriers never fire further apart than this.",[570,807,808,813,818],{},[588,809,810],{},[324,811,812],{},"commit-barrier.interval-factor",[588,814,815],{},[324,816,817],{},"1.5",[588,819,820],{},"Cadence target as a multiple of measured commit duration.",[570,822,823,828,833],{},[588,824,825],{},[324,826,827],{},"commit-barrier.timeout-ms",[588,829,830],{},[324,831,832],{},"60000",[588,834,835,836,376,839,842,843,336],{},"Hard timeout for a commit; also cascades to the Kafka producer's ",[324,837,838],{},"transaction.timeout.ms",[324,840,841],{},"max.block.ms",", and ",[324,844,845],{},"delivery.timeout.ms",[397,847,849],{"className":399,"code":848,"language":401,"meta":402,"style":402},"stoatflow:\n  commit-barrier:\n    min-interval-ms: 100     # allow tighter commits for lower latency\n    max-interval-ms: 2000    # but never let an epoch run longer than 2s\n    interval-factor: 1.5\n",[324,850,851,857,864,878,891],{"__ignoreMap":402},[406,852,853,855],{"class":408,"line":409},[406,854,413],{"class":412},[406,856,417],{"class":416},[406,858,859,862],{"class":408,"line":420},[406,860,861],{"class":412},"  commit-barrier",[406,863,417],{"class":416},[406,865,866,869,871,874],{"class":408,"line":433},[406,867,868],{"class":412},"    min-interval-ms",[406,870,426],{"class":416},[406,872,873],{"class":541}," 100",[406,875,877],{"class":876},"s8zF2","     # allow tighter commits for lower latency\n",[406,879,880,883,885,888],{"class":408,"line":479},[406,881,882],{"class":412},"    max-interval-ms",[406,884,426],{"class":416},[406,886,887],{"class":541}," 2000",[406,889,890],{"class":876},"    # but never let an epoch run longer than 2s\n",[406,892,893,896,898],{"class":408,"line":487},[406,894,895],{"class":412},"    interval-factor",[406,897,426],{"class":416},[406,899,900],{"class":541}," 1.5\n",[320,902,903,904,907,908,911],{},"Lower the band for lower end-to-end latency (more frequent, smaller commits); raise it for higher throughput (fewer, larger commits). The ",[324,905,906],{},"interval-factor"," controls how aggressively the cadence tracks commit cost: ",[324,909,910],{},"1.0"," is back-to-back, higher values leave more idle gap between commits.",[738,913,915],{"id":914},"epoch-size-self-tunes-within-memory-and-count-bounds","Epoch size self-tunes within memory and count bounds",[320,917,918,919,922],{},"An ",[347,920,921],{},"epoch"," is the batch of records between two commit barriers. The runtime sizes each epoch automatically, tracking the dispatch rate and the per-record state-write cost so it can keep uncommitted state bounded — small for high-fan-out stateful topologies (FK joins, multi-way joins, where one input record cascades into many state writes) and large for lightweight stateless ones. You don't set the epoch size; you set the bounds it operates within.",[564,924,925,935],{},[567,926,927],{},[570,928,929,931,933],{},[573,930,753],{},[573,932,578],{},[573,934,758],{},[583,936,937,953,966,985,1006],{},[570,938,939,944,950],{},[588,940,941],{},[324,942,943],{},"state.uncommitted-max-bytes",[588,945,946,949],{},[324,947,948],{},"268435456"," (256 MB)",[588,951,952],{},"Hard limit on total uncommitted state bytes across all stores. The dominant bound for stateful, high-fan-out topologies.",[570,954,955,960,963],{},[588,956,957],{},[324,958,959],{},"commit-barrier.max-epoch-records",[588,961,962],{},"unset (no hard cap)",[588,964,965],{},"Optional hard ceiling on records per epoch.",[570,967,968,973,978],{},[588,969,970],{},[324,971,972],{},"commit-barrier.initial-max-epoch-records",[588,974,975],{},[324,976,977],{},"4096",[588,979,980,981,984],{},"Conservative cap for the first epoch(s), before the runtime has measured the topology. ",[324,982,983],{},"-1"," disables it.",[570,986,987,992,997],{},[588,988,989],{},[324,990,991],{},"caching.max-estimated-bytes",[588,993,994,996],{},[324,995,948],{}," (256 MiB)",[588,998,999,1002,1003,1005],{},[347,1000,1001],{},"Per-store"," cap on estimated emission-cache bytes; exceeding it fires an early cache-pressure commit. The global ",[324,1004,943],{}," ceiling measures a superset and normally fires first.",[570,1007,1008,1013,1016],{},[588,1009,1010],{},[324,1011,1012],{},"caching.max-entries",[588,1014,1015],{},"unbounded (opt-in)",[588,1017,1018,1019,1022],{},"Optional ",[347,1020,1021],{},"per-store"," entry-count cap — a lever for high-cardinality workloads that the byte estimate can't express. Setting a finite value makes workloads exceeding it early-commit.",[397,1024,1026],{"className":399,"code":1025,"language":401,"meta":402,"style":402},"stoatflow:\n  state:\n    uncommitted-max-bytes: 268435456   # 256 MB — raise on large containers, lower on small\n  commit-barrier:\n    initial-max-epoch-records: 4096    # cap startup epochs before adaptation kicks in\n    max-epoch-records: 50000           # optional hard ceiling\n",[324,1027,1028,1034,1041,1054,1060,1073],{"__ignoreMap":402},[406,1029,1030,1032],{"class":408,"line":409},[406,1031,413],{"class":412},[406,1033,417],{"class":416},[406,1035,1036,1039],{"class":408,"line":420},[406,1037,1038],{"class":412},"  state",[406,1040,417],{"class":416},[406,1042,1043,1046,1048,1051],{"class":408,"line":433},[406,1044,1045],{"class":412},"    uncommitted-max-bytes",[406,1047,426],{"class":416},[406,1049,1050],{"class":541}," 268435456",[406,1052,1053],{"class":876},"   # 256 MB — raise on large containers, lower on small\n",[406,1055,1056,1058],{"class":408,"line":479},[406,1057,861],{"class":412},[406,1059,417],{"class":416},[406,1061,1062,1065,1067,1070],{"class":408,"line":487},[406,1063,1064],{"class":412},"    initial-max-epoch-records",[406,1066,426],{"class":416},[406,1068,1069],{"class":541}," 4096",[406,1071,1072],{"class":876},"    # cap startup epochs before adaptation kicks in\n",[406,1074,1075,1078,1080,1083],{"class":408,"line":498},[406,1076,1077],{"class":412},"    max-epoch-records",[406,1079,426],{"class":416},[406,1081,1082],{"class":541}," 50000",[406,1084,1085],{"class":876},"           # optional hard ceiling\n",[705,1087,1089],{"color":707,"icon":1088},"i-lucide-info",[320,1090,1091,1092,1095],{},"The adaptive sizing ",[347,1093,1094],{},"algorithm"," — how the runtime converges on an epoch size from its measurements — is an implementation concern and lives in the source. What you configure are the public bounds: the memory limit it must not exceed, the optional record ceiling, and the startup cap. Within those, it self-tunes; you do not hand-set epoch sizes per workload.",[320,1097,1098,1099,1102],{},"Sizing your ",[324,1100,1101],{},"uncommitted-max-bytes"," to the container is the main lever for stateful topologies. As a starting point, leave roughly half the container's available memory (after JVM heap, RocksDB, and non-heap) as headroom:",[564,1104,1105,1119],{},[567,1106,1107],{},[570,1108,1109,1112,1116],{},[573,1110,1111],{},"Container memory",[573,1113,1114],{},[324,1115,1101],{},[573,1117,1118],{},"Rationale",[583,1120,1121,1136,1147],{},[570,1122,1123,1126,1133],{},[588,1124,1125],{},"4 GiB",[588,1127,1128,1129,1132],{},"1 GiB (",[324,1130,1131],{},"1073741824",")",[588,1134,1135],{},"~2.5 GB available after heap\u002FRocksDB; 1 GB leaves headroom.",[570,1137,1138,1141,1144],{},[588,1139,1140],{},"8 GiB",[588,1142,1143],{},"1-2 GiB",[588,1145,1146],{},"More room for GC and Kafka client buffers.",[570,1148,1149,1152,1155],{},[588,1150,1151],{},"16 GiB",[588,1153,1154],{},"2-4 GiB",[588,1156,1157],{},"Recommended for heavy stateful topologies.",[320,1159,1160,1161,1164,1165,376,1168,1171,1172,1175,1176,336],{},"The ",[324,1162,1163],{},"\u002Fmetrics"," endpoint exposes per-epoch counters — ",[324,1166,1167],{},"stoatflow.barrier.epoch.actual.records",[324,1169,1170],{},"stoatflow.barrier.epoch.memory.cap",", and a ",[324,1173,1174],{},"stoatflow.barrier.trigger.total"," counter tagged by what ended each epoch (time, record count, memory pressure, or per-store cache pressure) — so you can see which bound is binding and adjust the right one. See ",[329,1177,195],{"href":196},[738,1179,1181],{"id":1180},"fixed-knobs-you-set-directly","Fixed knobs you set directly",[320,1183,1184],{},"These do not adapt; the value you set is the value used.",[564,1186,1187,1198],{},[567,1188,1189],{},[570,1190,1191,1193,1195],{},[573,1192,753],{},[573,1194,578],{},[573,1196,1197],{},"Notes",[583,1199,1200,1214,1227,1247],{},[570,1201,1202,1207,1211],{},[588,1203,1204],{},[324,1205,1206],{},"lanes.count",[588,1208,1209],{},[324,1210,608],{},[588,1212,1213],{},"Per-key parallelism. Higher = more concurrency, more queues.",[570,1215,1216,1221,1225],{},[588,1217,1218],{},[324,1219,1220],{},"lanes.queue-capacity",[588,1222,1223],{},[324,1224,621],{},[588,1226,624],{},[570,1228,1229,1234,1238],{},[588,1230,1231],{},[324,1232,1233],{},"processing-guarantee",[588,1235,1236],{},[324,1237,595],{},[588,1239,695,1240,1243,1244,336],{},[324,1241,1242],{},"AT_LEAST_ONCE"," for lower commit latency where duplicates are tolerable — see ",[329,1245,1246],{"href":53},"Exactly-once",[570,1248,1249,1254,1259],{},[588,1250,1251],{},[324,1252,1253],{},"watermark.max-out-of-orderness-ms",[588,1255,1256],{},[324,1257,1258],{},"10000",[588,1260,1261,1262,336],{},"Event-time slack — see ",[329,1263,67],{"href":68},[385,1265,1267],{"id":1266},"rocksdb-presets-and-tuning","RocksDB presets and tuning",[320,1269,1270,1271,1274],{},"State stores default to RocksDB with a ",[347,1272,1273],{},"bounded ~256 MB memory budget"," (block cache + memtables), as opposed to Kafka Streams' unbounded RocksDB defaults. You select a memory profile with a single key.",[738,1276,1278],{"id":1277},"presets","Presets",[397,1280,1282],{"className":399,"code":1281,"language":401,"meta":402,"style":402},"stoatflow:\n  rocks-db:\n    preset: DEFAULT   # DEFAULT | LOW_MEMORY | HIGH_PERFORMANCE\n    backend: AUTO     # AUTO | FFM | JNI\n",[324,1283,1284,1290,1297,1310],{"__ignoreMap":402},[406,1285,1286,1288],{"class":408,"line":409},[406,1287,413],{"class":412},[406,1289,417],{"class":416},[406,1291,1292,1295],{"class":408,"line":420},[406,1293,1294],{"class":412},"  rocks-db",[406,1296,417],{"class":416},[406,1298,1299,1302,1304,1307],{"class":408,"line":433},[406,1300,1301],{"class":412},"    preset",[406,1303,426],{"class":416},[406,1305,1306],{"class":429}," DEFAULT",[406,1308,1309],{"class":876},"   # DEFAULT | LOW_MEMORY | HIGH_PERFORMANCE\n",[406,1311,1312,1315,1317,1320],{"class":408,"line":479},[406,1313,1314],{"class":412},"    backend",[406,1316,426],{"class":416},[406,1318,1319],{"class":429}," AUTO",[406,1321,1322],{"class":876},"     # AUTO | FFM | JNI\n",[564,1324,1325,1341],{},[567,1326,1327],{},[570,1328,1329,1332,1335,1338],{},[573,1330,1331],{},"Preset",[573,1333,1334],{},"Total memory",[573,1336,1337],{},"Composition",[573,1339,1340],{},"Use for",[583,1342,1343,1358,1373],{},[570,1344,1345,1349,1352,1355],{},[588,1346,1347],{},[324,1348,379],{},[588,1350,1351],{},"64 MB",[588,1353,1354],{},"32 MB block cache + 32 MB memtables",[588,1356,1357],{},"Development, CI, constrained containers. More frequent compaction and cache eviction.",[570,1359,1360,1364,1367,1370],{},[588,1361,1362],{},[324,1363,375],{},[588,1365,1366],{},"256 MB",[588,1368,1369],{},"128 MB block cache + 128 MB memtables",[588,1371,1372],{},"Most production workloads with moderate state.",[570,1374,1375,1379,1382,1385],{},[588,1376,1377],{},[324,1378,382],{},[588,1380,1381],{},"1 GB",[588,1383,1384],{},"512 MB block cache + 512 MB memtables",[588,1386,1387],{},"High-throughput workloads with large state. Needs more memory.",[320,1389,1390,1391,1394],{},"The memory budget is ",[347,1392,1393],{},"shared across all stores"," — one block cache and one write-buffer manager bound total RocksDB memory regardless of how many state stores the topology declares.",[738,1396,1398],{"id":1397},"backend","Backend",[320,1400,1401,1404,1405,1408,1409,1412,1413,1416,1417,1419,1420,1422,1423,1426,1427,1430,1431,1433],{},[324,1402,1403],{},"backend: AUTO"," (default) picks each runtime's faster path: the Foreign Function & Memory API (",[324,1406,1407],{},"FFM",") on the JVM — lower per-call overhead, no virtual-thread pinning — and the ",[324,1410,1411],{},"rocksdbjni"," bindings (",[324,1414,1415],{},"JNI",") under a native image. Set ",[324,1418,1407],{}," or ",[324,1421,1415],{}," explicitly to force a specific backend. Both require the ",[324,1424,1425],{},"--enable-native-access=ALL-UNNAMED"," JVM flag (the ",[324,1428,1429],{},"io.stoatflow"," Gradle plugin sets it — see ",[329,1432,18],{"href":19},").",[738,1435,1437],{"id":1436},"beyond-the-presets","Beyond the presets",[320,1439,1440],{},"The three presets cover the common cases. For finer control there are two escape hatches, neither exposed as additional YAML keys:",[341,1442,1443,1604],{},[344,1444,1445,1448,1449,1452,1453],{},[347,1446,1447],{},"Custom total-memory budget (programmatic)."," When constructing the config in code rather than YAML, ",[324,1450,1451],{},"RocksDBConfig.withTotalMemory(bytes)"," produces a config with cache, memtables, and file sizes scaled proportionally to any budget (minimum 32 MB):",[1454,1455,1457,1521],"code-tabs",{"group":1456},"lang",[397,1458,1463],{"className":1459,"code":1460,"filename":1461,"language":1462,"meta":402,"style":402},"language-kotlin shiki shiki-themes vitesse-light","import io.stoatflow.core.state.rocksdb.RocksDBConfig\n\n\u002F\u002F 512 MB total, scaled proportionally\nval rocks = RocksDBConfig.withTotalMemory(512L * 1024 * 1024)\n","Kotlin","kotlin",[324,1464,1465,1474,1478,1483],{"__ignoreMap":402},[406,1466,1467,1470],{"class":408,"line":409},[406,1468,1469],{"class":529},"import",[406,1471,1473],{"class":1472},"sySUi"," io.stoatflow.core.state.rocksdb.RocksDBConfig\n",[406,1475,1476],{"class":408,"line":420},[406,1477,502],{"emptyLinePlaceholder":501},[406,1479,1480],{"class":408,"line":433},[406,1481,1482],{"class":876},"\u002F\u002F 512 MB total, scaled proportionally\n",[406,1484,1485,1488,1492,1495,1498,1501,1504,1507,1511,1514,1516,1518],{"class":408,"line":479},[406,1486,1487],{"class":529},"val",[406,1489,1491],{"class":1490},"suHK_"," rocks ",[406,1493,1494],{"class":416},"=",[406,1496,1497],{"class":1490}," RocksDBConfig.",[406,1499,1500],{"class":1472},"withTotalMemory",[406,1502,1503],{"class":1490},"(",[406,1505,1506],{"class":541},"512L",[406,1508,1510],{"class":1509},"si04Y"," *",[406,1512,1513],{"class":541}," 1024",[406,1515,1510],{"class":1509},[406,1517,1513],{"class":541},[406,1519,1520],{"class":1490},")\n",[397,1522,1527],{"className":1523,"code":1524,"filename":1525,"language":1526,"meta":402,"style":402},"language-java shiki shiki-themes vitesse-light","import io.stoatflow.core.state.rocksdb.RocksDBConfig;\n\n\u002F\u002F 512 MB total, scaled proportionally\nRocksDBConfig rocks = RocksDBConfig.withTotalMemory(512L * 1024 * 1024);\n","Java","java",[324,1528,1529,1563,1567,1571],{"__ignoreMap":402},[406,1530,1531,1533,1536,1538,1540,1542,1545,1547,1550,1552,1555,1557,1560],{"class":408,"line":409},[406,1532,1469],{"class":529},[406,1534,1535],{"class":1490}," io",[406,1537,336],{"class":416},[406,1539,413],{"class":1490},[406,1541,336],{"class":416},[406,1543,1544],{"class":1490},"core",[406,1546,336],{"class":416},[406,1548,1549],{"class":1490},"state",[406,1551,336],{"class":416},[406,1553,1554],{"class":1490},"rocksdb",[406,1556,336],{"class":416},[406,1558,1559],{"class":1490},"RocksDBConfig",[406,1561,1562],{"class":416},";\n",[406,1564,1565],{"class":408,"line":420},[406,1566,502],{"emptyLinePlaceholder":501},[406,1568,1569],{"class":408,"line":433},[406,1570,1482],{"class":876},[406,1572,1573,1575,1579,1582,1585,1587,1589,1591,1593,1595,1597,1599,1601],{"class":408,"line":479},[406,1574,1559],{"class":1490},[406,1576,1578],{"class":1577},"svycV"," rocks",[406,1580,1581],{"class":416}," =",[406,1583,1584],{"class":1577}," RocksDBConfig",[406,1586,336],{"class":416},[406,1588,1500],{"class":1472},[406,1590,1503],{"class":416},[406,1592,1506],{"class":541},[406,1594,1510],{"class":1509},[406,1596,1513],{"class":541},[406,1598,1510],{"class":1509},[406,1600,1513],{"class":541},[406,1602,1603],{"class":416},");\n",[344,1605,1606,1609,1610,1613,1614,1617,1618,1621,1622,1625,1626,376,1629,1632,1633,1636,1637,1640,1641,336,1644],{},[347,1607,1608],{},"Per-store RocksDB options (config setter)."," For per-store tuning — different settings for write-heavy versus read-heavy stores, custom compression, compaction strategy — set ",[324,1611,1612],{},"rocks-db-config-setter"," to the fully qualified name of a class implementing ",[324,1615,1616],{},"RocksDBConfigSetter",". Its ",[324,1619,1620],{},"configure(storeName, options)"," runs for every store with ",[324,1623,1624],{},"options"," pre-populated from the active preset, so you can branch on the store name and override per-store knobs such as ",[324,1627,1628],{},"options.cf.maxWriteBufferNumber",[324,1630,1631],{},"options.cf.writeBufferSize",", or ",[324,1634,1635],{},"options.table.useRibbonFilter",". Shared memory resources (the block cache and write-buffer manager) are framework-managed and ",[347,1638,1639],{},"cannot"," be overridden per store — set the total memory budget globally via the preset or ",[324,1642,1643],{},"RocksDBConfig.withTotalMemory(...)",[397,1645,1647],{"className":399,"code":1646,"language":401,"meta":402,"style":402},"stoatflow:\n  rocks-db-config-setter: com.example.MyRocksDBConfigSetter\n",[324,1648,1649,1655],{"__ignoreMap":402},[406,1650,1651,1653],{"class":408,"line":409},[406,1652,413],{"class":412},[406,1654,417],{"class":416},[406,1656,1657,1660,1662],{"class":408,"line":420},[406,1658,1659],{"class":412},"  rocks-db-config-setter",[406,1661,426],{"class":416},[406,1663,1664],{"class":429}," com.example.MyRocksDBConfigSetter\n",[705,1666,1668],{"color":1667,"icon":80},"warning",[320,1669,1670,1671,1674,1675,1677,1678,1681],{},"Ribbon filters (",[324,1672,1673],{},"useRibbonFilter",", default on) only take effect on the ",[347,1676,1407],{}," backend — the JNI bindings fall back to Bloom filters. If you switch to ",[324,1679,1680],{},"backend: JNI",", expect a slightly larger filter memory footprint at the same false-positive rate.",[385,1683,1685],{"id":1684},"where-to-go-next","Where to go next",[341,1687,1688,1693,1698,1703],{},[344,1689,1690,1692],{},[329,1691,331],{"href":73}," — how env vars, system properties, YAML, and programmatic config layer and override each other.",[344,1694,1695,1697],{},[329,1696,335],{"href":249}," — workload-driven tuning walkthroughs for latency, throughput, and heavy-state topologies.",[344,1699,1700,1702],{},[329,1701,281],{"href":282}," — every key, default, and env override in one table.",[344,1704,1705,1707],{},[329,1706,195],{"href":196}," — the per-epoch and commit-cadence counters that show which bound is binding.",[1709,1710,1711],"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 .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 .sbBg2, html code.shiki .sbBg2{--shiki-default:#1E754F}html pre.shiki code .s-TwI, html code.shiki .s-TwI{--shiki-default:#2F798A}html pre.shiki code .s8zF2, html code.shiki .s8zF2{--shiki-default:#A0ADA0}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 .si04Y, html code.shiki .si04Y{--shiki-default:#AB5959}html pre.shiki code .svycV, html code.shiki .svycV{--shiki-default:#B07D48}",{"title":402,"searchDepth":420,"depth":420,"links":1713},[1714,1715,1720,1725],{"id":387,"depth":420,"text":388},{"id":716,"depth":420,"text":717,"children":1716},[1717,1718,1719],{"id":740,"depth":433,"text":741},{"id":914,"depth":433,"text":915},{"id":1180,"depth":433,"text":1181},{"id":1266,"depth":420,"text":1267,"children":1721},[1722,1723,1724],{"id":1277,"depth":433,"text":1278},{"id":1397,"depth":433,"text":1398},{"id":1436,"depth":433,"text":1437},{"id":1684,"depth":420,"text":1685},"Why a minimal StoatFlow config runs well — the opinionated defaults, the parts that self-tune within bounds you set, and the RocksDB presets and tuning knobs you can change.","md",{},{"icon":170},"how-to",{"title":167,"description":1726},"8PfJv_gkyiM0vu4JuTJewHWueCBbfyRAQgvXBMwZIp8",[1734,1736],{"title":162,"path":163,"stem":164,"description":1735,"icon":165,"children":-1},"The runtime.* section of application.yaml — HTTP server, metrics, info\u002Fconfig endpoints, health checks — plus logging levels and Kafka client passthrough.",{"title":172,"path":173,"stem":174,"description":1737,"icon":175,"children":-1},"Pass arbitrary consumer, producer, and restoration-consumer properties through to the Kafka clients, and understand which properties StoatFlow forces for correctness.",1783713360691]