[{"data":1,"prerenderedAt":1687},["ShallowReactive",2],{"navigation":3,"\u002Fdocs\u002Fruntime\u002Fnative-image":314,"\u002Fdocs\u002Fruntime\u002Fnative-image-surround":1682},[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":215,"body":316,"description":1675,"extension":1676,"meta":1677,"navigation":1678,"pageType":1679,"path":216,"seo":1680,"stem":217,"__hash__":1681},"docs\u002F1.docs\u002F5.runtime\u002F8.native-image.md",{"type":317,"value":318,"toc":1657},"minimark",[319,333,344,406,411,422,563,567,590,676,709,712,744,782,796,801,806,843,891,895,898,926,943,969,976,983,1001,1013,1017,1024,1081,1094,1098,1105,1112,1147,1163,1167,1170,1224,1228,1244,1248,1258,1294,1321,1325,1328,1419,1434,1438,1455,1461,1475,1486,1490,1597,1601,1653],[320,321,322,323,327,328,332],"p",{},"A StoatFlow application compiles to a GraalVM ",[324,325,326],"strong",{},"native image"," — a standalone binary with fast start-up, a small footprint, and (with the right GC) steady-state CPU and tail latency on par with the JVM. The opt-in is one line, because the framework already ships the native-image metadata for everything ",[329,330,331],"em",{},"it"," touches; the only per-app work is the metadata for your own serde value classes.",[320,334,335,336,339,340,343],{},"This is the most advanced part of the build. Set up a working JVM build first (",[337,338,33],"a",{"href":34},"); for most deployments the ",[337,341,342],{"href":211},"JVM container image"," is the simpler, better-trodden path. Reach for native when cold-start time or per-instance memory is the binding constraint.",[345,346,347],"tldr-panel",{},[348,349,350,366,384,390,400],"ul",{},[351,352,353,356,357,361,362,365],"li",{},[324,354,355],{},"Opt in:"," Gradle ",[358,359,360],"code",{},"nativeImage { enabled.set(true) }"," · Maven activate ",[358,363,364],{},"-Pstoatflow-native",".",[351,367,368,371,372,375,376,379,380,383],{},[324,369,370],{},"Build it:"," the ",[324,373,374],{},"containerized"," build is recommended — ",[358,377,378],{},".\u002Fgradlew nativeDockerBuild"," \u002F ",[358,381,382],{},"mvn stoatflow:native-docker-build",". It pins the build glibc, wires the GC + reproducible epoch, and bakes the container-aware heap entrypoint.",[351,385,386,389],{},[324,387,388],{},"Use Oracle GraalVM + G1 for any stateful (RocksDB) workload"," — Community Edition ships Serial GC only, which can't carry an allocation-heavy state path. The containerized build already uses the Oracle GraalVM builder.",[351,391,392,395,396,399],{},[324,393,394],{},"The RocksDB backend auto-tunes:"," FFM on the JVM, JNI under native image (",[358,397,398],{},"AUTO",", the default) — each runtime gets its faster path with no config.",[351,401,402,405],{},[324,403,404],{},"You add only your serde value classes"," to the native metadata; the framework covers its own engine, Kafka client, RocksDB, and runtime surface.",[407,408,410],"h2",{"id":409},"one-line-opt-in","One-line opt-in",[320,412,413,414,417,418,421],{},"A StoatFlow app doesn't start from a blank GraalVM configuration. The framework bundles its native-image metadata, discovered automatically by classpath. Turning native image on applies GraalVM's build plugin, the curated ",[358,415,416],{},"--initialize-at-run-time"," flags RocksDB and the Kafka SASL client need, and the ",[358,419,420],{},"nativeDockerBuild"," task:",[423,424,426,530],"code-tabs",{"group":425},"build",[427,428,434],"pre",{"className":429,"code":430,"filename":431,"language":432,"meta":433,"style":433},"language-kotlin shiki shiki-themes vitesse-light","\u002F\u002F build.gradle.kts\nstoatflow {\n    mainClass.set(\"com.example.MainKt\")\n    nativeImage {\n        enabled.set(true)\n        gc.set(\"G1\")        \u002F\u002F Oracle GraalVM; omit for Serial GC (stateless only)\n    }\n}\n","Gradle","kotlin","",[358,435,436,445,456,475,483,499,518,524],{"__ignoreMap":433},[437,438,441],"span",{"class":439,"line":440},"line",1,[437,442,444],{"class":443},"s8zF2","\u002F\u002F build.gradle.kts\n",[437,446,448,452],{"class":439,"line":447},2,[437,449,451],{"class":450},"sySUi","stoatflow",[437,453,455],{"class":454},"suHK_"," {\n",[437,457,459,462,465,468,472],{"class":439,"line":458},3,[437,460,461],{"class":454},"    mainClass.",[437,463,464],{"class":450},"set",[437,466,467],{"class":454},"(",[437,469,471],{"class":470},"spphp","\"com.example.MainKt\"",[437,473,474],{"class":454},")\n",[437,476,478,481],{"class":439,"line":477},4,[437,479,480],{"class":450},"    nativeImage",[437,482,455],{"class":454},[437,484,486,489,491,493,497],{"class":439,"line":485},5,[437,487,488],{"class":454},"        enabled.",[437,490,464],{"class":450},[437,492,467],{"class":454},[437,494,496],{"class":495},"sbBg2","true",[437,498,474],{"class":454},[437,500,502,505,507,509,512,515],{"class":439,"line":501},6,[437,503,504],{"class":454},"        gc.",[437,506,464],{"class":450},[437,508,467],{"class":454},[437,510,511],{"class":470},"\"G1\"",[437,513,514],{"class":454},")        ",[437,516,517],{"class":443},"\u002F\u002F Oracle GraalVM; omit for Serial GC (stateless only)\n",[437,519,521],{"class":439,"line":520},7,[437,522,523],{"class":454},"    }\n",[437,525,527],{"class":439,"line":526},8,[437,528,529],{"class":454},"}\n",[427,531,536],{"className":532,"code":533,"filename":534,"language":535,"meta":433,"style":433},"language-xml shiki shiki-themes vitesse-light","\u003C!-- pom.xml — native config lives in \u003Cproperties>; activate with -Pstoatflow-native -->\n\u003Cproperties>\n  \u003Cstoatflow.mainClass>com.example.Main\u003C\u002Fstoatflow.mainClass>\n  \u003Cstoatflow.nativeImage.gc>G1\u003C\u002Fstoatflow.nativeImage.gc>\n\u003C\u002Fproperties>\n","Maven","xml",[358,537,538,543,548,553,558],{"__ignoreMap":433},[437,539,540],{"class":439,"line":440},[437,541,542],{},"\u003C!-- pom.xml — native config lives in \u003Cproperties>; activate with -Pstoatflow-native -->\n",[437,544,545],{"class":439,"line":447},[437,546,547],{},"\u003Cproperties>\n",[437,549,550],{"class":439,"line":458},[437,551,552],{},"  \u003Cstoatflow.mainClass>com.example.Main\u003C\u002Fstoatflow.mainClass>\n",[437,554,555],{"class":439,"line":477},[437,556,557],{},"  \u003Cstoatflow.nativeImage.gc>G1\u003C\u002Fstoatflow.nativeImage.gc>\n",[437,559,560],{"class":439,"line":485},[437,561,562],{},"\u003C\u002Fproperties>\n",[407,564,566],{"id":565},"build-it","Build it",[320,568,569,570,573,574,577,578,581,582,585,586,589],{},"The ",[324,571,572],{},"containerized build"," is the recommended path for any image you'll actually run. It compiles the native binary ",[329,575,576],{},"inside Docker"," from your prebuilt fat JAR, against a generic, repo-independent ",[358,579,580],{},"Dockerfile.native"," the build stages for you — so it pins the build-host glibc, wires the GC and the reproducible ",[358,583,584],{},"SOURCE_DATE_EPOCH",", stages the heap entrypoint, and applies the ",[358,587,588],{},"runtimeTarget",":",[423,591,592,630],{"group":425},[427,593,597],{"className":594,"code":595,"filename":431,"language":596,"meta":433,"style":433},"language-bash shiki shiki-themes vitesse-light",".\u002Fgradlew nativeDockerBuild\n# → \u003CimageName>:native  +  \u003CimageName>:\u003Cversion>-native\n\n# Quick local smoke-compile (host GraalVM, no Docker):\n.\u002Fgradlew nativeCompile\n","bash",[358,598,599,607,612,618,623],{"__ignoreMap":433},[437,600,601,604],{"class":439,"line":440},[437,602,603],{"class":450},".\u002Fgradlew",[437,605,606],{"class":470}," nativeDockerBuild\n",[437,608,609],{"class":439,"line":447},[437,610,611],{"class":443},"# → \u003CimageName>:native  +  \u003CimageName>:\u003Cversion>-native\n",[437,613,614],{"class":439,"line":458},[437,615,617],{"emptyLinePlaceholder":616},true,"\n",[437,619,620],{"class":439,"line":477},[437,621,622],{"class":443},"# Quick local smoke-compile (host GraalVM, no Docker):\n",[437,624,625,627],{"class":439,"line":485},[437,626,603],{"class":450},[437,628,629],{"class":470}," nativeCompile\n",[427,631,633],{"className":594,"code":632,"filename":534,"language":596,"meta":433,"style":433},"mvn package                          # build the fat JAR first\nmvn stoatflow:native-docker-build\n# → \u003CimageName>:native  +  \u003CimageName>:\u003Cversion>-native\n\n# Quick local smoke-compile (host GraalVM, no Docker):\nmvn -Pstoatflow-native package\n",[358,634,635,646,653,657,661,665],{"__ignoreMap":433},[437,636,637,640,643],{"class":439,"line":440},[437,638,639],{"class":450},"mvn",[437,641,642],{"class":470}," package",[437,644,645],{"class":443},"                          # build the fat JAR first\n",[437,647,648,650],{"class":439,"line":447},[437,649,639],{"class":450},[437,651,652],{"class":470}," stoatflow:native-docker-build\n",[437,654,655],{"class":439,"line":458},[437,656,611],{"class":443},[437,658,659],{"class":439,"line":477},[437,660,617],{"emptyLinePlaceholder":616},[437,662,663],{"class":439,"line":485},[437,664,622],{"class":443},[437,666,667,669,673],{"class":439,"line":501},[437,668,639],{"class":450},[437,670,672],{"class":671},"sEi1f"," -Pstoatflow-native",[437,674,675],{"class":470}," package\n",[320,677,678,679,682,683,686,687,690,691,694,695,698,699,701,702,705,706,365],{},"The containerized build stages a build context (",[358,680,681],{},"build\u002Fstoatflow-native\u002F"," for Gradle) holding the prebuilt ",[358,684,685],{},"app.jar",", the shared ",[358,688,689],{},"native-image.args"," argfile, the heap entrypoint, and a ",[358,692,693],{},"pgo\u002F"," directory, then runs ",[358,696,697],{},"native-image @native-image.args …"," against the bundled ",[358,700,580],{},". Detected platform: ",[358,703,704],{},"linux\u002Farm64"," on Apple Silicon, otherwise ",[358,707,708],{},"linux\u002Famd64",[320,710,711],{},"The pipeline, stage by stage:",[427,713,717],{"className":714,"code":715,"language":716,"meta":433,"style":433},"language-mermaid shiki shiki-themes vitesse-light","flowchart LR\n    SRC[\"your app +\u003Cbr\u002F>nativeImage.enabled\"] --> JAR[\"fat JAR\"]\n    JAR --> CTX[\"staged build context —\u003Cbr\u002F>app.jar · native-image.args ·\u003Cbr\u002F>heap entrypoint · pgo\u002F\"]\n    CTX --> NI[\"docker build —\u003Cbr\u002F>native-image @native-image.args\u003Cbr\u002F>on the Oracle GraalVM builder\"]\n    NI --> IMG[\"distroless image —\u003Cbr\u002F>runtime (heap entrypoint)\u003Cbr\u002F>or runtime-lean\"]\n","mermaid",[358,718,719,724,729,734,739],{"__ignoreMap":433},[437,720,721],{"class":439,"line":440},[437,722,723],{"class":454},"flowchart LR\n",[437,725,726],{"class":439,"line":447},[437,727,728],{"class":454},"    SRC[\"your app +\u003Cbr\u002F>nativeImage.enabled\"] --> JAR[\"fat JAR\"]\n",[437,730,731],{"class":439,"line":458},[437,732,733],{"class":454},"    JAR --> CTX[\"staged build context —\u003Cbr\u002F>app.jar · native-image.args ·\u003Cbr\u002F>heap entrypoint · pgo\u002F\"]\n",[437,735,736],{"class":439,"line":477},[437,737,738],{"class":454},"    CTX --> NI[\"docker build —\u003Cbr\u002F>native-image @native-image.args\u003Cbr\u002F>on the Oracle GraalVM builder\"]\n",[437,740,741],{"class":439,"line":485},[437,742,743],{"class":454},"    NI --> IMG[\"distroless image —\u003Cbr\u002F>runtime (heap entrypoint)\u003Cbr\u002F>or runtime-lean\"]\n",[745,746,749],"callout",{"color":747,"icon":748},"info","i-lucide-info",[320,750,751,754,755,757,758,761,762,765,766,769,770,773,774,777,778,781],{},[324,752,753],{},"Why build in Docker?"," A native binary links the build host's glibc and needs that version (or newer) at runtime. The bundled ",[358,756,580],{}," builds on a pinned ",[324,759,760],{},"Oracle GraalVM"," image (",[358,763,764],{},"native-image:25-ol9",", Oracle Linux 9 \u002F glibc 2.34) and runs on a distroless ",[358,767,768],{},"cc-debian12"," base (glibc 2.36), so the binary doesn't crash-loop on a ",[358,771,772],{},"GLIBC_2.xx not found"," mismatch — and you get G1 + PGO, which Community Edition lacks. A raw host ",[358,775,776],{},"nativeCompile"," is best treated as a ",[329,779,780],{},"does-it-compile"," smoke check.",[745,783,785],{"color":784,"icon":70},"warning",[320,786,787,788,791,792,795],{},"Native compilation is resource-hungry: budget ",[324,789,790],{},"8 GB+ RAM"," and ",[324,793,794],{},"15–20 minutes",". The containerized build needs only Docker — no local GraalVM install.",[797,798,800],"h3",{"id":799},"runtime-target","Runtime target",[320,802,803,805],{},[358,804,588],{}," selects the final image stage:",[348,807,808,832],{},[351,809,810,815,816,819,820,823,824,827,828,831],{},[324,811,812],{},[358,813,814],{},"runtime"," (default) — a ",[358,817,818],{},"cc-debian12:debug"," distroless base with a busybox shell so the ",[324,821,822],{},"container-aware heap entrypoint"," can size ",[358,825,826],{},"-Xmx"," from the container memory limit, reserving ",[358,829,830],{},"STOATFLOW_ROCKSDB_MB"," for RocksDB off-heap (recommended).",[351,833,834,839,840,842],{},[324,835,836],{},[358,837,838],{},"runtime-lean"," — a minimal ",[358,841,768],{}," distroless base, no shell, no entrypoint: SubstrateVM sizes the heap itself. Smallest possible image.",[423,844,845,873],{"group":425},[427,846,848],{"className":429,"code":847,"filename":431,"language":432,"meta":433,"style":433},"stoatflow { nativeImage { runtimeTarget.set(\"runtime-lean\") } }\n",[358,849,850],{"__ignoreMap":433},[437,851,852,854,857,860,863,865,867,870],{"class":439,"line":440},[437,853,451],{"class":450},[437,855,856],{"class":454}," { ",[437,858,859],{"class":450},"nativeImage",[437,861,862],{"class":454}," { runtimeTarget.",[437,864,464],{"class":450},[437,866,467],{"class":454},[437,868,869],{"class":470},"\"runtime-lean\"",[437,871,872],{"class":454},") } }\n",[427,874,876],{"className":532,"code":875,"filename":534,"language":535,"meta":433,"style":433},"\u003Cproperties>\n  \u003Cstoatflow.nativeImage.runtimeTarget>runtime-lean\u003C\u002Fstoatflow.nativeImage.runtimeTarget>\n\u003C\u002Fproperties>\n",[358,877,878,882,887],{"__ignoreMap":433},[437,879,880],{"class":439,"line":440},[437,881,547],{},[437,883,884],{"class":439,"line":447},[437,885,886],{},"  \u003Cstoatflow.nativeImage.runtimeTarget>runtime-lean\u003C\u002Fstoatflow.nativeImage.runtimeTarget>\n",[437,888,889],{"class":439,"line":458},[437,890,562],{},[407,892,894],{"id":893},"the-garbage-collector-matters-most","The garbage collector matters most",[320,896,897],{},"The single most important native-image decision is the GC — far more than the foreign-function path or anything exotic.",[348,899,900,914],{},[351,901,902,905,906,909,910,913],{},[324,903,904],{},"GraalVM Community Edition ships only Serial GC"," for native image. Serial is fine for a ",[329,907,908],{},"stateless"," transform, but it ",[324,911,912],{},"cannot carry an allocation-heavy stateful (RocksDB) workload"," — under load a stateful app on Serial falls behind the input and never catches up (we measured a 112× end-to-end latency blowup).",[351,915,916,918,919,791,922,925],{},[324,917,760],{}," (free for production under the GFTC licence, and what the containerized build already uses) unlocks ",[324,920,921],{},"G1",[324,923,924],{},"PGO",". Switching Serial → G1 — one flag — takes a stateful app straight back to JVM parity.",[320,927,928,929,932,933,936,937,939,940,365],{},"The rule: ",[324,930,931],{},"stateless → Serial is acceptable; stateful → use G1."," Set ",[358,934,935],{},"gc"," to ",[358,938,921],{}," and the containerized build passes it through to ",[358,941,942],{},"native-image",[745,944,945],{"color":747,"icon":748},[320,946,947,950,951,953,954,957,958,960,961,964,965,968],{},[324,948,949],{},"Memory is tunable, not free."," Under Serial GC a native image is tiny. Under G1 the heap reservation is sized from ",[358,952,826],{},", and the container entrypoint hands the JVM most of the container — so a ",[329,955,956],{},"tiny-heap stateless"," app can use more RSS than on the JVM. For those, pin a tight ",[358,959,826],{}," (an env override, no rebuild) to recover the win. Stateful apps, whose live footprint is larger, already land ",[324,962,963],{},"below"," the JVM's total memory. See ",[337,966,967],{"href":249},"Tuning"," for how GC interacts with commit cadence.",[407,970,972,973,975],{"id":971},"the-rocksdb-backend-auto-ffm-jni","The RocksDB backend: ",[358,974,398],{}," (FFM ⇄ JNI)",[320,977,978,979,982],{},"StoatFlow talks to RocksDB's C API through two interchangeable backends, and the faster one ",[324,980,981],{},"inverts"," between runtimes:",[348,984,985,995],{},[351,986,987,990,991,994],{},[324,988,989],{},"On the JVM, FFM wins."," The JIT intrinsifies its ",[358,992,993],{},"critical(false)"," downcalls down to nearly a direct C call.",[351,996,997,1000],{},[324,998,999],{},"Under native image, JNI wins."," SubstrateVM has no JIT, so that intrinsification never fires and a plain JNI call ends up cheaper (~8% less CPU, better P99 in our measurements).",[320,1002,1003,1004,1008,1009,1012],{},"So the default backend is ",[324,1005,1006],{},[358,1007,398],{},": FFM on the JVM, JNI under native image. ",[324,1010,1011],{},"You don't configure anything"," — each runtime is routed to its faster path automatically, and the brittle FFM-under-native machinery is off the default path entirely.",[407,1014,1016],{"id":1015},"where-reachability-metadata-lives","Where reachability metadata lives",[320,1018,1019,1020,1023],{},"GraalVM's closed-world analysis needs metadata for everything reached via reflection, JNI, resources, and FFM foreign downcalls. StoatFlow ships this metadata ",[324,1021,1022],{},"inside the module JARs"," — not in per-app config files:",[1025,1026,1027,1043],"table",{},[1028,1029,1030],"thead",{},[1031,1032,1033,1037,1040],"tr",{},[1034,1035,1036],"th",{},"Module",[1034,1038,1039],{},"Metadata path",[1034,1041,1042],{},"Covers",[1044,1045,1046,1066],"tbody",{},[1031,1047,1048,1054,1059],{},[1049,1050,1051],"td",{},[358,1052,1053],{},"stoatflow-core",[1049,1055,1056],{},[358,1057,1058],{},"META-INF\u002Fnative-image\u002Fio.stoatflow\u002Fcore\u002F",[1049,1060,1061,1062,1065],{},"Kafka serde reflection, the Kafka client, RocksDB (both the JNI bindings ",[324,1063,1064],{},"and"," the FFM foreign downcalls), JCTools, zstd",[1031,1067,1068,1073,1078],{},[1049,1069,1070],{},[358,1071,1072],{},"stoatflow-runtime",[1049,1074,1075],{},[358,1076,1077],{},"META-INF\u002Fnative-image\u002Fio.stoatflow\u002Fruntime\u002F",[1049,1079,1080],{},"the YAML config binding, Logback, Micrometer\u002FHdrHistogram, and the rest of the runtime stack",[320,1082,1083,1084,1086,1087,1089,1090,1093],{},"Any app that depends on ",[358,1085,1072],{}," (and transitively ",[358,1088,1053],{},") inherits the correct metadata automatically through GraalVM's classpath discovery. You copy or generate ",[324,1091,1092],{},"nothing"," for the StoatFlow surface — only for your own types, next.",[407,1095,1097],{"id":1096},"custom-serde-metadata","Custom serde metadata",[320,1099,1100,1101,1104],{},"The closed-world compiler still needs to know about ",[324,1102,1103],{},"your"," types — the value classes you serialize\u002Fdeserialize — because anything reflective, JNI, or FFM must be declared up front, or it fails the first time that code path runs (never at build time).",[320,1106,1107,1108,1111],{},"The reliable way to generate it is the ",[324,1109,1110],{},"GraalVM tracing agent",": run your app (or its tests) on the JVM with the agent attached, exercise every code path, and it writes the metadata. Drop the result under your module's resources so GraalVM discovers it by classpath:",[427,1113,1115],{"className":594,"code":1114,"language":596,"meta":433,"style":433},"# Run your app\u002Ftests on the JVM with the tracing agent, driving real traffic:\njava -agentlib:native-image-agent=config-output-dir=src\u002Fmain\u002Fresources\u002FMETA-INF\u002Fnative-image\u002Fcom.example\u002Fword-count \\\n     --enable-preview --enable-native-access=ALL-UNNAMED -jar build\u002Flibs\u002Fword-count-all.jar\n",[358,1116,1117,1122,1133],{"__ignoreMap":433},[437,1118,1119],{"class":439,"line":440},[437,1120,1121],{"class":443},"# Run your app\u002Ftests on the JVM with the tracing agent, driving real traffic:\n",[437,1123,1124,1127,1130],{"class":439,"line":447},[437,1125,1126],{"class":450},"java",[437,1128,1129],{"class":671}," -agentlib:native-image-agent=config-output-dir=src\u002Fmain\u002Fresources\u002FMETA-INF\u002Fnative-image\u002Fcom.example\u002Fword-count",[437,1131,1132],{"class":671}," \\\n",[437,1134,1135,1138,1141,1144],{"class":439,"line":458},[437,1136,1137],{"class":671},"     --enable-preview",[437,1139,1140],{"class":671}," --enable-native-access=ALL-UNNAMED",[437,1142,1143],{"class":671}," -jar",[437,1145,1146],{"class":470}," build\u002Flibs\u002Fword-count-all.jar\n",[745,1148,1149],{"color":784,"icon":80},[320,1150,1151,1154,1155,1158,1159,1162],{},[324,1152,1153],{},"Drive every path before you trust the binary."," Closed-world compilation moves failures from build time to ",[329,1156,1157],{},"first-record"," time. A ",[358,1160,1161],{},"MissingReflectionRegistrationError"," only surfaces when its code path first executes — so exercise your serdes, punctuators, joins, and error paths under the agent.",[407,1164,1166],{"id":1165},"snares-gotchas","Snares & gotchas",[320,1168,1169],{},"The discoveries that cost an afternoon each:",[348,1171,1172,1186,1201],{},[351,1173,1174,1177,1178,1181,1182,1185],{},[324,1175,1176],{},"Avro + Schema Registry is the worst offender."," Confluent's stack instantiates classes by name from its own config defaults (e.g. ",[358,1179,1180],{},"NullContextNameStrategy","), Jackson-deserializes the registry's REST entities, and native image disables URL protocols by default — so the schema fetch fails until you add ",[358,1183,1184],{},"--enable-url-protocols=http,https",". The tracing agent catches the config-default classes in one pass; it's the surer route for anything Avro.",[351,1187,1188,1197,1198,1200],{},[324,1189,1190,1193,1194,365],{},[358,1191,1192],{},"reachability-metadata.json"," shadows the legacy ",[358,1195,1196],{},"reflection-config.json"," When both are present the newer format wins and silently drops the old file's registrations. Keep your metadata in the newer ",[358,1199,1192],{},"; don't run the two side by side.",[351,1202,1203,1206,1207,1210,1211,1214,1215,1218,1219,1223],{},[324,1204,1205],{},"PGO profiles only dump on clean shutdown."," A streaming app runs forever, so extracting a ",[358,1208,1209],{},".iprof"," takes plumbing — the bundled native entrypoint forwards ",[358,1212,1213],{},"SIGTERM"," to the child process so ",[358,1216,1217],{},"kill -TERM 1"," drains and dumps the profile. (See the ",[337,1220,1222],{"href":1221},"\u002Fblog\u002Fnative-image-g1-pgo-jni-vs-ffm","deep-dive",".)",[407,1225,1227],{"id":1226},"profile-guided-optimisation-pgo","Profile-Guided Optimisation (PGO)",[320,1229,1230,1231,1233,1234,1237,1238,1240,1241,365],{},"PGO is the CPU lever — a release-time, two-pass build (compile an instrumented binary, run it under representative load to collect a ",[358,1232,1209],{},", rebuild with the profile). It's purely a CPU optimisation (latency\u002Fthroughput are already at parity under G1) and trims the residual AOT-vs-JIT gap by another ~13–17%. It's ",[324,1235,1236],{},"Oracle-GraalVM-only"," and adds real build time, so treat it as a release step, not a per-change one. The build context includes a ",[358,1239,693],{}," directory where the collected profile is staged. The full recipe — instrumenting, extracting the profile from a long-running server, and rebuilding — is in the ",[337,1242,1243],{"href":1221},"engineering deep-dive",[407,1245,1247],{"id":1246},"what-the-build-passes-to-native-image","What the build passes to native-image",[320,1249,1250,1251,1253,1254,1257],{},"The static flags come from a single bundled ",[358,1252,689],{}," (identical for Gradle, Maven, and the containerized build); ",[358,1255,1256],{},"--gc"," and PGO are layered on dynamically. You write none of these by hand:",[348,1259,1260,1279],{},[351,1261,1262,1265,1266,1265,1269,1272,1273,1265,1276,365],{},[358,1263,1264],{},"-H:+JNI",", ",[358,1267,1268],{},"-H:+ReportExceptionStackTraces",[358,1270,1271],{},"-H:+AddAllCharsets",", the Kotlin resource includes, ",[358,1274,1275],{},"--enable-preview",[358,1277,1278],{},"--no-fallback",[351,1280,1281,1283,1284,1265,1287,1265,1290,1293],{},[358,1282,416],{}," for ",[358,1285,1286],{},"org.rocksdb",[358,1288,1289],{},"org.rocksdb.RocksDB",[358,1291,1292],{},"org.rocksdb.util.Environment",", the FFM RocksDB bindings, and the Kafka SASL client authenticator — these load native libraries or read runtime state and must initialize when the binary starts, not when it's compiled.",[320,1295,1296,1297,1300,1301,1304,1305,1308,1309,1312,1313,1316,1317,1320],{},"If your own code (or a dependency) needs run-time initialization, add it via ",[358,1298,1299],{},"additionalInitializeAtRunTime"," (Gradle) \u002F extend the ",[358,1302,1303],{},"native-maven-plugin"," ",[358,1306,1307],{},"\u003CbuildArgs>"," (Maven); drop a curated entry with ",[358,1310,1311],{},"removeInitializeAtRunTime",". The full enumeration is in the ",[337,1314,291],{"href":1315},"\u002Fdocs\u002Freference\u002Fgradle-plugin-reference#native-image-defaults",". The typical trigger is a build-time error: ",[358,1318,1319],{},"Classes that should be initialized at run time got initialized during image building"," — add the named class and rebuild.",[407,1322,1324],{"id":1323},"verify-it-runs","Verify it runs",[320,1326,1327],{},"After building, run the image and check the same health and metrics endpoints as the JVM runtime:",[427,1329,1331],{"className":594,"code":1330,"language":596,"meta":433,"style":433},"docker run -d --name sf-native \\\n  -e KAFKA_BOOTSTRAP_SERVERS=host.docker.internal:9092 \\\n  -e STOATFLOW_LICENSE_KEY=\"key\u002F...your key...\" \\\n  -p 8080:8080 \\\n  my-app:native\n\ncurl -s localhost:8080\u002Fhealth\u002Fready\ncurl -s localhost:8080\u002Finfo\n",[358,1332,1333,1352,1362,1380,1390,1395,1399,1410],{"__ignoreMap":433},[437,1334,1335,1338,1341,1344,1347,1350],{"class":439,"line":440},[437,1336,1337],{"class":450},"docker",[437,1339,1340],{"class":470}," run",[437,1342,1343],{"class":671}," -d",[437,1345,1346],{"class":671}," --name",[437,1348,1349],{"class":470}," sf-native",[437,1351,1132],{"class":671},[437,1353,1354,1357,1360],{"class":439,"line":447},[437,1355,1356],{"class":671},"  -e",[437,1358,1359],{"class":470}," KAFKA_BOOTSTRAP_SERVERS=host.docker.internal:9092",[437,1361,1132],{"class":671},[437,1363,1364,1366,1369,1373,1376,1378],{"class":439,"line":458},[437,1365,1356],{"class":671},[437,1367,1368],{"class":470}," STOATFLOW_LICENSE_KEY=",[437,1370,1372],{"class":1371},"sSP4y","\"",[437,1374,1375],{"class":470},"key\u002F...your key...",[437,1377,1372],{"class":1371},[437,1379,1132],{"class":671},[437,1381,1382,1385,1388],{"class":439,"line":477},[437,1383,1384],{"class":671},"  -p",[437,1386,1387],{"class":470}," 8080:8080",[437,1389,1132],{"class":671},[437,1391,1392],{"class":439,"line":485},[437,1393,1394],{"class":470},"  my-app:native\n",[437,1396,1397],{"class":439,"line":501},[437,1398,617],{"emptyLinePlaceholder":616},[437,1400,1401,1404,1407],{"class":439,"line":520},[437,1402,1403],{"class":450},"curl",[437,1405,1406],{"class":671}," -s",[437,1408,1409],{"class":470}," localhost:8080\u002Fhealth\u002Fready\n",[437,1411,1412,1414,1416],{"class":439,"line":526},[437,1413,1403],{"class":450},[437,1415,1406],{"class":671},[437,1417,1418],{"class":470}," localhost:8080\u002Finfo\n",[320,1420,1421,1422,1424,1425,1427,1428,1433],{},"If the process exits at startup with ",[358,1423,1319],{}," or a ",[358,1426,1161],{},", the fix is metadata: add the class to ",[337,1429,1431],{"href":1430},"#what-the-build-passes-to-native-image",[358,1432,1299],{},", or register the reflective access via the tracing agent, then rebuild.",[407,1435,1437],{"id":1436},"whats-covered-and-what-isnt-yet","What's covered — and what isn't yet",[320,1439,1440,1443,1444,1447,1448,1451,1452,365],{},[324,1441,1442],{},"Covered today"," (benchmarked under load): String, Protobuf, and Avro + Schema Registry serdes; stateless and stateful (RocksDB) topologies; exactly-once. With Oracle GraalVM + G1 + PGO, the apps we measured run within ",[324,1445,1446],{},"−4% to +10% CPU"," of the JVM, ",[324,1449,1450],{},"latency equal-or-better everywhere",", and ",[324,1453,1454],{},"memory below the JVM on the stateful apps",[320,1456,1457,1460],{},[324,1458,1459],{},"Not yet mapped"," — these pull in reflection\u002FJNI surface that still needs native metadata:",[348,1462,1463,1469],{},[351,1464,1465,1468],{},[324,1466,1467],{},"Kafka client security"," — SASL (SCRAM, GSSAPI\u002FKerberos), OAuth bearer, and mTLS.",[351,1470,1471,1474],{},[324,1472,1473],{},"Compression codecs beyond zstd"," — snappy, lz4, gzip.",[320,1476,1477,1478,1480,1481,1485],{},"If you hit a ",[358,1479,1161],{}," on one of these, the tracing agent is your first move — and ",[337,1482,1484],{"href":1483},"\u002Fcontact","let us know",", so we can fold the metadata into the framework.",[407,1487,1489],{"id":1488},"knob-reference","Knob reference",[1025,1491,1492,1513],{},[1028,1493,1494],{},[1031,1495,1496,1499,1506],{},[1034,1497,1498],{},"Capability",[1034,1500,1501,1502,1505],{},"Gradle (",[358,1503,1504],{},"stoatflow { nativeImage { … } }",")",[1034,1507,1508,1509,1512],{},"Maven (",[358,1510,1511],{},"\u003Cproperties>"," \u002F build)",[1044,1514,1515,1530,1545,1560,1579],{},[1031,1516,1517,1520,1525],{},[1049,1518,1519],{},"Enable",[1049,1521,1522],{},[358,1523,1524],{},"enabled.set(true)",[1049,1526,1527,1528],{},"activate ",[358,1529,364],{},[1031,1531,1532,1535,1540],{},[1049,1533,1534],{},"Garbage collector",[1049,1536,1537],{},[358,1538,1539],{},"gc.set(\"G1\")",[1049,1541,1542],{},[358,1543,1544],{},"\u003Cstoatflow.nativeImage.gc>G1\u003C\u002F…>",[1031,1546,1547,1550,1555],{},[1049,1548,1549],{},"Runtime image stage",[1049,1551,1552],{},[358,1553,1554],{},"runtimeTarget.set(\"runtime-lean\")",[1049,1556,1557],{},[358,1558,1559],{},"\u003Cstoatflow.nativeImage.runtimeTarget>…\u003C\u002F…>",[1031,1561,1562,1567,1572],{},[1049,1563,1564,1565],{},"Add ",[358,1566,416],{},[1049,1568,1569],{},[358,1570,1571],{},"additionalInitializeAtRunTime.add(\"…\")",[1049,1573,1574,1575,1304,1577],{},"extend the ",[358,1576,1303],{},[358,1578,1307],{},[1031,1580,1581,1586,1591],{},[1049,1582,1583,1584],{},"Drop a curated ",[358,1585,416],{},[1049,1587,1588],{},[358,1589,1590],{},"removeInitializeAtRunTime.add(\"…\")",[1049,1592,1593,1596],{},[358,1594,1595],{},"\u003Cstoatflow.nativeImage.removeInitializeAtRunTime>…\u003C\u002F…>"," (CSV)",[407,1598,1600],{"id":1599},"further-reading","Further reading",[348,1602,1603,1611,1620,1632,1640],{},[351,1604,1605,1610],{},[324,1606,1607],{},[337,1608,1609],{"href":1221},"The engineering deep-dive"," — G1, PGO, why JNI beats FFM under AOT, and the full benchmark matrix.",[351,1612,1613,1619],{},[324,1614,1615],{},[337,1616,1618],{"href":1617},"\u002Fproduct\u002Fbenchmarks","Benchmarks"," — the numbers behind the claims here.",[351,1621,1622,1626,1627,1631],{},[324,1623,1624],{},[337,1625,291],{"href":292}," · ",[324,1628,1629],{},[337,1630,296],{"href":297}," — every native knob, task, and default.",[351,1633,1634,1639],{},[324,1635,1636],{},[337,1637,1638],{"href":211},"Docker"," — the JVM container image (Jib), the simpler default deployment target.",[351,1641,1642,791,1647,1652],{},[324,1643,1644],{},[337,1645,1646],{"href":229},"Kubernetes",[324,1648,1649],{},[337,1650,1651],{"href":239},"Probes"," — deploying the image and wiring liveness\u002Freadiness.",[1654,1655,1656],"style",{},"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 .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 .sEi1f, html code.shiki .sEi1f{--shiki-default:#A65E2B}html pre.shiki code .sSP4y, html code.shiki .sSP4y{--shiki-default:#B5695977}",{"title":433,"searchDepth":447,"depth":447,"links":1658},[1659,1660,1663,1664,1666,1667,1668,1669,1670,1671,1672,1673,1674],{"id":409,"depth":447,"text":410},{"id":565,"depth":447,"text":566,"children":1661},[1662],{"id":799,"depth":458,"text":800},{"id":893,"depth":447,"text":894},{"id":971,"depth":447,"text":1665},"The RocksDB backend: AUTO (FFM ⇄ JNI)",{"id":1015,"depth":447,"text":1016},{"id":1096,"depth":447,"text":1097},{"id":1165,"depth":447,"text":1166},{"id":1226,"depth":447,"text":1227},{"id":1246,"depth":447,"text":1247},{"id":1323,"depth":447,"text":1324},{"id":1436,"depth":447,"text":1437},{"id":1488,"depth":447,"text":1489},{"id":1599,"depth":447,"text":1600},"Compile your StoatFlow app to a GraalVM native binary — a one-line opt-in. The framework ships its own reflection\u002FJNI\u002FFFM metadata; you choose the GC, optionally PGO, and add metadata only for your own serde value classes.","md",{},{"icon":218},"how-to",{"title":215,"description":1675},"0iU2QetDzn4nGLUk1AHGUx5UmB0_vJ0Ct8oFgdPB1GA",[1683,1685],{"title":210,"path":211,"stem":212,"description":1684,"icon":213,"children":-1},"Build a container image for your StoatFlow app with the StoatFlow build conventions (Jib) — base image, JVM flags, reproducible builds, container-aware heap sizing, ports and env — on Gradle or Maven.",{"title":225,"path":221,"stem":222,"description":1686,"icon":226,"children":-1},"The deployment model for operators — one active instance and why two corrupt state, the two HA tiers (fast restart and opt-in hot standby), and a map of the operating pages.",1783713362490]