[{"data":1,"prerenderedAt":601},["ShallowReactive",2],{"docs-nav:en":3,"docs:\u002Fdocs\u002Finfra\u002Fdeployment":134},[4],{"title":5,"path":6,"stem":7,"children":8},"Docs","\u002Fdocs","docs",[9,12,16,20,24,42,63,92,113],{"title":10,"path":6,"stem":11},"What is Fougere","docs\u002Findex",{"title":13,"path":14,"stem":15},"Getting started","\u002Fdocs\u002Fgetting-started","docs\u002F01.getting-started",{"title":17,"path":18,"stem":19},"Existing Nuxt app","\u002Fdocs\u002Fexisting-app","docs\u002F02.existing-app",{"title":21,"path":22,"stem":23},"The CLI","\u002Fdocs\u002Fcli","docs\u002F03.cli",{"title":25,"path":26,"stem":27,"children":28,"page":41},"Concepts","\u002Fdocs\u002Fconcepts","docs\u002F2.concepts",[29,33,37],{"title":30,"path":31,"stem":32},"Philosophy","\u002Fdocs\u002Fconcepts\u002Fphilosophy","docs\u002F2.concepts\u002F1.philosophy",{"title":34,"path":35,"stem":36},"The Frond","\u002Fdocs\u002Fconcepts\u002Ffrond","docs\u002F2.concepts\u002F2.frond",{"title":38,"path":39,"stem":40},"The shortest path","\u002Fdocs\u002Fconcepts\u002Fshortest-path","docs\u002F2.concepts\u002F3.shortest-path",false,{"title":43,"path":44,"stem":45,"children":46,"page":41},"Schema","\u002Fdocs\u002Fschema","docs\u002F3.schema",[47,51,55,59],{"title":48,"path":49,"stem":50},"Entities","\u002Fdocs\u002Fschema\u002Fentities","docs\u002F3.schema\u002F1.entities",{"title":52,"path":53,"stem":54},"Views","\u002Fdocs\u002Fschema\u002Fviews","docs\u002F3.schema\u002F2.views",{"title":56,"path":57,"stem":58},"The identity card","\u002Fdocs\u002Fschema\u002Fcard","docs\u002F3.schema\u002F3.card",{"title":60,"path":61,"stem":62},"Standard Schema","\u002Fdocs\u002Fschema\u002Fstandard-schema","docs\u002F3.schema\u002F4.standard-schema",{"title":64,"path":65,"stem":66,"children":67,"page":41},"Business","\u002Fdocs\u002Fbusiness","docs\u002F4.business",[68,72,76,80,84,88],{"title":69,"path":70,"stem":71},"Handlers","\u002Fdocs\u002Fbusiness\u002Fhandlers","docs\u002F4.business\u002F1.handlers",{"title":73,"path":74,"stem":75},"Presenters","\u002Fdocs\u002Fbusiness\u002Fpresenters","docs\u002F4.business\u002F2.presenters",{"title":77,"path":78,"stem":79},"Collectors","\u002Fdocs\u002Fbusiness\u002Fcollectors","docs\u002F4.business\u002F3.collectors",{"title":81,"path":82,"stem":83},"Errors","\u002Fdocs\u002Fbusiness\u002Ferrors","docs\u002F4.business\u002F4.errors",{"title":85,"path":86,"stem":87},"Seeds","\u002Fdocs\u002Fbusiness\u002Fseeds","docs\u002F4.business\u002F5.seeds",{"title":89,"path":90,"stem":91},"Facts","\u002Fdocs\u002Fbusiness\u002Ffacts","docs\u002F4.business\u002F6.facts",{"title":93,"path":94,"stem":95,"children":96,"page":41},"Client","\u002Fdocs\u002Fclient","docs\u002F5.client",[97,101,105,109],{"title":98,"path":99,"stem":100},"Queries & commands","\u002Fdocs\u002Fclient\u002Fqueries-commands","docs\u002F5.client\u002F1.queries-commands",{"title":102,"path":103,"stem":104},"Forms","\u002Fdocs\u002Fclient\u002Fforms","docs\u002F5.client\u002F2.forms",{"title":106,"path":107,"stem":108},"Session","\u002Fdocs\u002Fclient\u002Fsession","docs\u002F5.client\u002F3.session",{"title":110,"path":111,"stem":112},"invoke","\u002Fdocs\u002Fclient\u002Finvoke","docs\u002F5.client\u002F4.invoke",{"title":114,"path":115,"stem":116,"children":117,"page":41},"Infrastructure","\u002Fdocs\u002Finfra","docs\u002F6.infra",[118,122,126,130],{"title":119,"path":120,"stem":121},"The gradient","\u002Fdocs\u002Finfra\u002Fgradient","docs\u002F6.infra\u002F1.gradient",{"title":123,"path":124,"stem":125},"Surfaces — REST & GraphQL","\u002Fdocs\u002Finfra\u002Fsurfaces","docs\u002F6.infra\u002F2.surfaces",{"title":127,"path":128,"stem":129},"Deployment","\u002Fdocs\u002Finfra\u002Fdeployment","docs\u002F6.infra\u002F3.deployment",{"title":131,"path":132,"stem":133},"Hosts","\u002Fdocs\u002Finfra\u002Fhosts","docs\u002F6.infra\u002F4.hosts",{"id":135,"title":127,"body":136,"description":596,"extension":597,"meta":598,"navigation":459,"path":128,"seo":599,"stem":129,"__hash__":600},"docs_en\u002Fdocs\u002F6.infra\u002F3.deployment.md",{"type":137,"value":138,"toc":591},"minimark",[139,143,152,157,284,291,301,305,316,387,390,521,532,536,552,570,577,587],[140,141,127],"h1",{"id":142},"deployment",[144,145,146,147,151],"p",{},"A Fougere app is a Nitro app plus one thing Nitro doesn't know about: ",[148,149,150],"strong",{},"the Frond sources\nare read at runtime"," (scan, AST parse, jiti load). This page is what deploying this very\nsite taught — the checklist, then the Docker realization.",[153,154,156],"h2",{"id":155},"the-runtime-checklist","The runtime checklist",[158,159,160,174,220,240,246,256,270],"ol",{},[161,162,163,169,170,173],"li",{},[148,164,165],{},[166,167,168],"code",{},".output\u002F"," — the Nitro build (",[166,171,172],{},"pnpm build",").",[161,175,176,179,180,183,184,187,188,191,192,195,196,195,199,195,202,205,206,195,209,195,212,215,216,219],{},[148,177,178],{},"The Frond sources"," — next to ",[166,181,182],{},".output",": the scanner reads them from ",[166,185,186],{},"process.cwd()","\nat boot. ",[166,189,190],{},"fronds\u002F**\u002F*.ts",", and when the root itself is the Frond, the convention\ndirectories at the root (",[166,193,194],{},"entities\u002F",", ",[166,197,198],{},"handlers\u002F",[166,200,201],{},"presenters\u002F",[166,203,204],{},"collectors\u002F",",\n",[166,207,208],{},"seeds\u002F",[166,210,211],{},"services\u002F",[166,213,214],{},"repositories\u002F","). Copying ",[166,217,218],{},"fronds\u002F"," alone leaves a flat app with\nno domain and no error — see the boot log below.",[161,221,222,225,226,205,229,195,232,235,236,239],{},[148,223,224],{},"A resolvable node_modules for the fronds"," — those sources import ",[166,227,228],{},"@fougere\u002Fschema",[166,230,231],{},"@fougere\u002Fcore",[166,233,234],{},"better-auth","… by name. ",[166,237,238],{},"pnpm deploy --prod"," produces exactly that\nclosure; hand-picking packages is re-implementing a tracer, don't.",[161,241,242,245],{},[148,243,244],{},"A TS with the compiler JS API"," (5.9 — TS 7 has none) — dynamically imported by the\nscanner, invisible to Nitro's tracer.",[161,247,248,251,252,255],{},[148,249,250],{},"Complete lazy packages"," — Nitro's pnpm trace of ",[166,253,254],{},"jiti"," is partial (its babel\ntransform is loaded on demand). Replace it with the real package.",[161,257,258,264,265,269],{},[148,259,260,261],{},"A writable ",[166,262,263],{},".data\u002F"," — the SQLite file and Nuxt Content's index live there. It is\nthe ",[266,267,268],"em",{},"only"," thing to persist: one volume.",[161,271,272,275,276,279,280,283],{},[148,273,274],{},"Secrets by env"," — ",[166,277,278],{},"AUTH_SECRET"," (32+ chars), the public ",[166,281,282],{},"SITE_URL",".",[144,285,286,287,290],{},"The verification signal is the boot log — ",[148,288,289],{},"not"," a 200 on pages (SSR renders happily with\nzero fronds loaded):",[292,293,298],"pre",{"className":294,"code":296,"language":297},[295],"language-text","INF [boot:app] scanned 2 frond(s) in 467ms      ← this line\n{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":[]}            ← and one envelope call\n","text",[166,299,296],{"__ignoreMap":300},"",[153,302,304],{"id":303},"docker","Docker",[144,306,307,308,311,312,315],{},"The site ships a working pair — ",[166,309,310],{},"site\u002FDockerfile"," + ",[166,313,314],{},"site\u002Fdocker-compose.yml",":",[292,317,321],{"className":318,"code":319,"language":320,"meta":300,"style":300},"language-bash shiki shiki-themes material-theme-lighter github-light github-dark","SITE_AUTH_SECRET='…32+ chars…' SITE_URL='https:\u002F\u002Fyour-domain' \\\n  docker compose -f site\u002Fdocker-compose.yml up -d --build\n","bash",[166,322,323,362],{"__ignoreMap":300},[324,325,328,332,336,340,344,346,349,351,353,356,358],"span",{"class":326,"line":327},"line",1,[324,329,331],{"class":330},"su5hD","SITE_AUTH_SECRET",[324,333,335],{"class":334},"smGrS","=",[324,337,339],{"class":338},"sjJ54","'",[324,341,343],{"class":342},"s_sjI","…32+ chars…",[324,345,339],{"class":338},[324,347,348],{"class":330}," SITE_URL",[324,350,335],{"class":334},[324,352,339],{"class":338},[324,354,355],{"class":342},"https:\u002F\u002Fyour-domain",[324,357,339],{"class":338},[324,359,361],{"class":360},"sbgvK"," \\\n",[324,363,365,368,371,375,378,381,384],{"class":326,"line":364},2,[324,366,367],{"class":342},"  docker",[324,369,370],{"class":342}," compose",[324,372,374],{"class":373},"stzsN"," -f",[324,376,377],{"class":342}," site\u002Fdocker-compose.yml",[324,379,380],{"class":342}," up",[324,382,383],{"class":373}," -d",[324,385,386],{"class":373}," --build\n",[144,388,389],{},"The Dockerfile realizes the checklist in two stages:",[292,391,395],{"className":392,"code":393,"language":394,"meta":300,"style":300},"language-dockerfile shiki shiki-themes material-theme-lighter github-light github-dark","# build stage: install workspace → build packages → build site\nRUN pnpm --filter \".\u002Fpackages\u002F**\" -r run build \\\n && pnpm --filter \"@fougere\u002Fsite\" run build\n# the frond-resolution closure, by pnpm itself:\nRUN pnpm --filter \"@fougere\u002Fsite\" deploy --prod --legacy \u002Fdeploy\n# complete jiti's partial trace + add TS 5.9\n\n# run stage: node:22-slim, non-root\nCOPY --from=build \u002Frepo\u002Fsite\u002F.output .\u002F.output\nCOPY --from=build \u002Frepo\u002Fsite\u002Ffronds  .\u002Ffronds\nCOPY --from=build \u002Fdeploy\u002Fnode_modules .\u002Fnode_modules\nVOLUME \u002Fapp\u002F.data\nCMD [\"node\", \".output\u002Fserver\u002Findex.mjs\"]\n","dockerfile",[166,396,397,403,418,430,436,448,454,461,467,476,484,492,501],{"__ignoreMap":300},[324,398,399],{"class":326,"line":327},[324,400,402],{"class":401},"sutJx","# build stage: install workspace → build packages → build site\n",[324,404,405,409,412,415],{"class":326,"line":364},[324,406,408],{"class":407},"sw1J6","RUN",[324,410,411],{"class":330}," pnpm --filter ",[324,413,414],{"class":342},"\".\u002Fpackages\u002F**\"",[324,416,417],{"class":330}," -r run build \\\n",[324,419,421,424,427],{"class":326,"line":420},3,[324,422,423],{"class":330}," && pnpm --filter ",[324,425,426],{"class":342},"\"@fougere\u002Fsite\"",[324,428,429],{"class":330}," run build\n",[324,431,433],{"class":326,"line":432},4,[324,434,435],{"class":401},"# the frond-resolution closure, by pnpm itself:\n",[324,437,439,441,443,445],{"class":326,"line":438},5,[324,440,408],{"class":407},[324,442,411],{"class":330},[324,444,426],{"class":342},[324,446,447],{"class":330}," deploy --prod --legacy \u002Fdeploy\n",[324,449,451],{"class":326,"line":450},6,[324,452,453],{"class":401},"# complete jiti's partial trace + add TS 5.9\n",[324,455,457],{"class":326,"line":456},7,[324,458,460],{"emptyLinePlaceholder":459},true,"\n",[324,462,464],{"class":326,"line":463},8,[324,465,466],{"class":401},"# run stage: node:22-slim, non-root\n",[324,468,470,473],{"class":326,"line":469},9,[324,471,472],{"class":407},"COPY",[324,474,475],{"class":330}," --from=build \u002Frepo\u002Fsite\u002F.output .\u002F.output\n",[324,477,479,481],{"class":326,"line":478},10,[324,480,472],{"class":407},[324,482,483],{"class":330}," --from=build \u002Frepo\u002Fsite\u002Ffronds  .\u002Ffronds\n",[324,485,487,489],{"class":326,"line":486},11,[324,488,472],{"class":407},[324,490,491],{"class":330}," --from=build \u002Fdeploy\u002Fnode_modules .\u002Fnode_modules\n",[324,493,495,498],{"class":326,"line":494},12,[324,496,497],{"class":407},"VOLUME",[324,499,500],{"class":330}," \u002Fapp\u002F.data\n",[324,502,504,507,510,513,515,518],{"class":326,"line":503},13,[324,505,506],{"class":407},"CMD",[324,508,509],{"class":330}," [",[324,511,512],{"class":342},"\"node\"",[324,514,195],{"class":330},[324,516,517],{"class":342},"\".output\u002Fserver\u002Findex.mjs\"",[324,519,520],{"class":330},"]\n",[144,522,523,524,527,528,531],{},"State lives in the ",[166,525,526],{},"site-data"," volume mounted at ",[166,529,530],{},"\u002Fapp\u002F.data"," — backups are one file copy.",[153,533,535],{"id":534},"splitting-in-production","Splitting in production",[144,537,538,539,542,543,546,547,551],{},"The same image model applies to a split: the host process serving a Frond needs items\n1–5 for ",[266,540,541],{},"its"," fronds, and the consumer declares it in ",[166,544,545],{},"remotes",". A dead host degrades to\ntyped 503s in pages (",[548,549,119],"a",{"href":550},"\u002Fdocs\u002Finfra\u002Fgradient#behaviour-after-a-split",");\nrestarting it is recovery — the consumer is never rebuilt.",[144,553,554,555,558,559,561,562,565,566,569],{},"Three things get called \"together\" and only one of them is required. The ",[148,556,557],{},"contract"," must\ntravel — the consumer has to know what the host serves. The ",[148,560,166],{}," need not: ",[166,563,564],{},"fougere sync"," reads the host's identity card and rebuilds a live schema locally, which is how a\nFrond written in another language is consumed at all. The ",[148,567,568],{},"ports"," must reach each other,\nand that is the only one a deployment decides.",[144,571,572,573,576],{},"The receiver binds loopback unless told otherwise, so the simplest split puts both\nprocesses on one machine: the same pod, or one image. ",[166,574,575],{},"hosts: ['0.0.0.0']"," widens it in\none line — and hands the operator what the loopback default was holding: a receiver\ntrusts the identity it is handed, so reaching it across a network means closing that\npath some other way (a mesh, a firewall, a sidecar) until identity is settled at the\nFrond.",[578,579,580],"blockquote",{},[144,581,582,583,586],{},"These steps are candidates for a future ",[166,584,585],{},"fougere build"," — a user should not have to\ndiscover them. Until then, this page is the contract.",[588,589,590],"style",{},"html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sbgvK, html code.shiki .sbgvK{--shiki-light:#E2931D;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .stzsN, html code.shiki .stzsN{--shiki-light:#91B859;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .sw1J6, html code.shiki .sw1J6{--shiki-light:#F76D47;--shiki-default:#D73A49;--shiki-dark:#F97583}",{"title":300,"searchDepth":364,"depth":364,"links":592},[593,594,595],{"id":155,"depth":364,"text":156},{"id":303,"depth":364,"text":304},{"id":534,"depth":364,"text":535},"What a Fougere app needs at runtime — learned by deploying this site.","md",{},{"title":127,"description":596},"82J2dbv9La50jVgDAuID0QRRL4IVumR7ztc8EGCx4G4",1786637819522]