[{"data":1,"prerenderedAt":595},["ShallowReactive",2],{"navigation":3,"page-\u002Fguides\u002Fdeploy-with-a-dockerfile":213,"surround-\u002Fguides\u002Fdeploy-with-a-dockerfile":590},[4,17,48,79,95,118,133,144,155,167,186],{"title":5,"path":6,"stem":7,"children":8,"icon":16,"exact":11},"Getting started","\u002Fgetting-started","1.getting-started\u002F1.index",[9,12],{"title":10,"path":6,"stem":7,"exact":11,"children":-1},"Introduction",true,{"title":13,"path":14,"stem":15,"exact":11,"children":-1},"Quickstart","\u002Fgetting-started\u002Fquickstart","1.getting-started\u002F2.quickstart","i-lucide-rocket",{"title":18,"path":19,"stem":20,"children":21,"icon":47,"exact":11},"Reference","\u002Freference","10.reference\u002F1.index",[22,23,27,31,35,39,43],{"title":18,"path":19,"stem":20,"exact":11,"children":-1},{"title":24,"path":25,"stem":26,"exact":11,"children":-1},"Variables","\u002Freference\u002Fvariables","10.reference\u002F2.variables",{"title":28,"path":29,"stem":30,"exact":11,"children":-1},"Hostnames and DNS","\u002Freference\u002Fhostnames-and-dns","10.reference\u002F3.hostnames-and-dns",{"title":32,"path":33,"stem":34,"exact":11,"children":-1},"Statuses","\u002Freference\u002Fstatuses","10.reference\u002F4.statuses",{"title":36,"path":37,"stem":38,"exact":11,"children":-1},"Limits","\u002Freference\u002Flimits","10.reference\u002F5.limits",{"title":40,"path":41,"stem":42,"exact":11,"children":-1},"Sizes","\u002Freference\u002Fsizes","10.reference\u002F6.sizes",{"title":44,"path":45,"stem":46,"exact":11,"children":-1},"The GitHub App","\u002Freference\u002Fgithub-app","10.reference\u002F7.github-app","i-lucide-book-open",{"title":49,"path":50,"stem":51,"children":52,"icon":78,"exact":11},"Troubleshooting","\u002Ftroubleshooting","11.troubleshooting\u002F1.index",[53,54,58,62,66,70,74],{"title":49,"path":50,"stem":51,"exact":11,"children":-1},{"title":55,"path":56,"stem":57,"exact":11,"children":-1},"Build failures","\u002Ftroubleshooting\u002Fbuild-failures","11.troubleshooting\u002F2.build-failures",{"title":59,"path":60,"stem":61,"exact":11,"children":-1},"Start and health failures","\u002Ftroubleshooting\u002Fstart-and-health-failures","11.troubleshooting\u002F3.start-and-health-failures",{"title":63,"path":64,"stem":65,"exact":11,"children":-1},"Reference failures","\u002Ftroubleshooting\u002Freference-failures","11.troubleshooting\u002F4.reference-failures",{"title":67,"path":68,"stem":69,"exact":11,"children":-1},"Failures that are Kuppit's","\u002Ftroubleshooting\u002Ffailures-that-are-kuppits","11.troubleshooting\u002F5.failures-that-are-kuppits",{"title":71,"path":72,"stem":73,"exact":11,"children":-1},"Domain issues","\u002Ftroubleshooting\u002Fdomain-issues","11.troubleshooting\u002F6.domain-issues",{"title":75,"path":76,"stem":77,"exact":11,"children":-1},"No preview for a pull request","\u002Ftroubleshooting\u002Fno-preview-for-a-pull-request","11.troubleshooting\u002F7.no-preview-for-a-pull-request","i-lucide-life-buoy",{"title":80,"path":81,"stem":82,"children":83,"icon":94,"exact":11},"Concepts","\u002Fconcepts","2.concepts\u002F1.index",[84,86,90],{"title":85,"path":81,"stem":82,"exact":11,"children":-1},"The Kuppit model",{"title":87,"path":88,"stem":89,"exact":11,"children":-1},"The application graph","\u002Fconcepts\u002Fthe-application-graph","2.concepts\u002F2.the-application-graph",{"title":91,"path":92,"stem":93,"exact":11,"children":-1},"How a service runs","\u002Fconcepts\u002Fhow-a-service-runs","2.concepts\u002F3.how-a-service-runs","i-lucide-shapes",{"title":96,"path":97,"stem":98,"children":99,"icon":117,"exact":11},"Deployments","\u002Fdeployments","3.deployments\u002F1.index",[100,101,105,109,113],{"title":96,"path":97,"stem":98,"exact":11,"children":-1},{"title":102,"path":103,"stem":104,"exact":11,"children":-1},"Builds","\u002Fdeployments\u002Fbuilds","3.deployments\u002F2.builds",{"title":106,"path":107,"stem":108,"exact":11,"children":-1},"Redeploy and roll back","\u002Fdeployments\u002Fredeploy-and-rollback","3.deployments\u002F3.redeploy-and-rollback",{"title":110,"path":111,"stem":112,"exact":11,"children":-1},"Logs","\u002Fdeployments\u002Flogs","3.deployments\u002F4.logs",{"title":114,"path":115,"stem":116,"exact":11,"children":-1},"When a deployment fails","\u002Fdeployments\u002Fwhen-a-deployment-fails","3.deployments\u002F5.when-a-deployment-fails","i-lucide-cloud-upload",{"title":119,"path":120,"stem":121,"children":122,"icon":132,"exact":11},"Resources","\u002Fresources","4.resources\u002F1.index",[123,124,128],{"title":119,"path":120,"stem":121,"exact":11,"children":-1},{"title":125,"path":126,"stem":127,"exact":11,"children":-1},"Web services","\u002Fresources\u002Fweb-services","4.resources\u002F2.web-services",{"title":129,"path":130,"stem":131,"exact":11,"children":-1},"PostgreSQL","\u002Fresources\u002Fpostgresql","4.resources\u002F3.postgresql","i-lucide-boxes",{"title":134,"icon":135,"path":136,"stem":137,"children":138,"page":143,"exact":11},"Configuration","i-lucide-sliders-horizontal","\u002Fconfiguration","5.configuration",[139],{"title":140,"path":141,"stem":142,"exact":11,"children":-1},"Environment variables","\u002Fconfiguration\u002Fvariables","5.configuration\u002F1.variables",false,{"title":145,"path":146,"stem":147,"children":148,"icon":154,"exact":11},"Networking","\u002Fnetworking","6.networking\u002F1.index",[149,150],{"title":145,"path":146,"stem":147,"exact":11,"children":-1},{"title":151,"path":152,"stem":153,"exact":11,"children":-1},"Reaching a database","\u002Fnetworking\u002Freaching-a-database","6.networking\u002F2.reaching-a-database","i-lucide-network",{"title":156,"path":157,"stem":158,"children":159,"icon":166,"exact":11},"Domains","\u002Fdomains","7.domains\u002F1.index",[160,162],{"title":161,"path":157,"stem":158,"exact":11,"children":-1},"Hostnames",{"title":163,"path":164,"stem":165,"exact":11,"children":-1},"Custom domains","\u002Fdomains\u002Fcustom-domains","7.domains\u002F2.custom-domains","i-lucide-globe",{"title":168,"path":169,"stem":170,"children":171,"icon":185,"exact":11},"Environments","\u002Fenvironments","8.environments\u002F1.index",[172,173,177,181],{"title":168,"path":169,"stem":170,"exact":11,"children":-1},{"title":174,"path":175,"stem":176,"exact":11,"children":-1},"Preview environments","\u002Fenvironments\u002Fpreview-environments","8.environments\u002F2.preview-environments",{"title":178,"path":179,"stem":180,"exact":11,"children":-1},"Named environments","\u002Fenvironments\u002Fnamed-environments","8.environments\u002F3.named-environments",{"title":182,"path":183,"stem":184,"exact":11,"children":-1},"Deleting an environment","\u002Fenvironments\u002Fdeleting-an-environment","8.environments\u002F4.deleting-an-environment","i-lucide-git-branch",{"title":187,"path":188,"stem":189,"children":190,"icon":212,"exact":11},"Guides","\u002Fguides","9.guides\u002F1.index",[191,192,196,200,204,208],{"title":187,"path":188,"stem":189,"exact":11,"children":-1},{"title":193,"path":194,"stem":195,"exact":11,"children":-1},"Deploy a Nuxt application","\u002Fguides\u002Fdeploy-a-nuxt-application","9.guides\u002F2.deploy-a-nuxt-application",{"title":197,"path":198,"stem":199,"exact":11,"children":-1},"Deploy a Next.js application","\u002Fguides\u002Fdeploy-a-nextjs-application","9.guides\u002F3.deploy-a-nextjs-application",{"title":201,"path":202,"stem":203,"exact":11,"children":-1},"Deploy an Express application","\u002Fguides\u002Fdeploy-an-express-application","9.guides\u002F4.deploy-an-express-application",{"title":205,"path":206,"stem":207,"exact":11,"children":-1},"Deploy with a Dockerfile","\u002Fguides\u002Fdeploy-with-a-dockerfile","9.guides\u002F5.deploy-with-a-dockerfile",{"title":209,"path":210,"stem":211,"exact":11,"children":-1},"Create a staging environment","\u002Fguides\u002Fcreate-a-staging-environment","9.guides\u002F6.create-a-staging-environment","i-lucide-map",{"id":214,"title":205,"badge":215,"body":216,"category":215,"description":584,"draft":143,"extension":585,"links":215,"meta":586,"navigation":11,"path":206,"seo":587,"sitemap":588,"stem":207,"__hash__":589},"docs\u002F9.guides\u002F5.deploy-with-a-dockerfile.md",null,{"type":217,"value":218,"toc":577},"minimark",[219,232,237,308,311,315,328,458,461,497,500,504,525,529,556,560,573],[220,221,222,223,227,228,231],"p",{},"A ",[224,225,226],"code",{},"Dockerfile"," in the root directory is the build. Kuppit chooses it over automatic detection whenever one is present, builds it exactly as written with a layer cache kept per service, and starts the image with ",[224,229,230],{},"PORT"," set to 8080. This is how anything that is not a Node.js application runs on Kuppit, and how a Node.js application runs when you want control of the image.",[233,234,236],"h2",{"id":235},"what-kuppit-detects","What Kuppit detects",[238,239,240,253],"table",{},[241,242,243],"thead",{},[244,245,246,250],"tr",{},[247,248,249],"th",{},"Setting",[247,251,252],{},"Value",[254,255,256,268,282,294],"tbody",{},[244,257,258,265],{},[259,260,261],"td",{},[262,263,264],"strong",{},"Strategy",[259,266,267],{},"Dockerfile, recommended whenever one exists.",[244,269,270,275],{},[259,271,272],{},[262,273,274],{},"Root directory",[259,276,277,278,281],{},"The build context. ",[224,279,280],{},"COPY"," paths are relative to it.",[244,283,284,289],{},[259,285,286],{},[262,287,288],{},"Dockerfile path",[259,290,291,293],{},[224,292,226],{},", relative to the root directory.",[244,295,296,301],{},[259,297,298],{},[262,299,300],{},"Port",[259,302,303,304,307],{},"8080, always. The runtime sets ",[224,305,306],{},"PORT=8080"," and routes there.",[220,309,310],{},"There is no framework, runtime, build or start command to set: the Dockerfile says all of it.",[233,312,314],{"id":313},"writing-the-dockerfile","Writing the Dockerfile",[220,316,317,318,320,321,324,325,327],{},"Listen on ",[224,319,230],{},", on all interfaces. ",[224,322,323],{},"EXPOSE"," is documentation; the routing follows ",[224,326,230],{},".",[329,330,335],"pre",{"className":331,"code":332,"filename":226,"language":333,"meta":334,"style":334},"language-dockerfile shiki shiki-themes material-theme-lighter github-light github-dark","FROM node:24-slim AS build\nWORKDIR \u002Fapp\nCOPY package.json pnpm-lock.yaml .\u002F\nRUN corepack enable && pnpm install --frozen-lockfile\nCOPY . .\nRUN pnpm build\n\nFROM node:24-slim\nWORKDIR \u002Fapp\nENV NODE_ENV=production\nCOPY --from=build \u002Fapp\u002F.output .\u002F.output\nCMD [\"node\", \".output\u002Fserver\u002Findex.mjs\"]\n","dockerfile","",[224,336,337,356,365,373,382,390,398,404,412,419,428,436],{"__ignoreMap":334},[338,339,342,346,350,353],"span",{"class":340,"line":341},"line",1,[338,343,345],{"class":344},"sw1J6","FROM",[338,347,349],{"class":348},"su5hD"," node:24-slim ",[338,351,352],{"class":344},"AS",[338,354,355],{"class":348}," build\n",[338,357,359,362],{"class":340,"line":358},2,[338,360,361],{"class":344},"WORKDIR",[338,363,364],{"class":348}," \u002Fapp\n",[338,366,368,370],{"class":340,"line":367},3,[338,369,280],{"class":344},[338,371,372],{"class":348}," package.json pnpm-lock.yaml .\u002F\n",[338,374,376,379],{"class":340,"line":375},4,[338,377,378],{"class":344},"RUN",[338,380,381],{"class":348}," corepack enable && pnpm install --frozen-lockfile\n",[338,383,385,387],{"class":340,"line":384},5,[338,386,280],{"class":344},[338,388,389],{"class":348}," . .\n",[338,391,393,395],{"class":340,"line":392},6,[338,394,378],{"class":344},[338,396,397],{"class":348}," pnpm build\n",[338,399,401],{"class":340,"line":400},7,[338,402,403],{"emptyLinePlaceholder":11},"\n",[338,405,407,409],{"class":340,"line":406},8,[338,408,345],{"class":344},[338,410,411],{"class":348}," node:24-slim\n",[338,413,415,417],{"class":340,"line":414},9,[338,416,361],{"class":344},[338,418,364],{"class":348},[338,420,422,425],{"class":340,"line":421},10,[338,423,424],{"class":344},"ENV",[338,426,427],{"class":348}," NODE_ENV=production\n",[338,429,431,433],{"class":340,"line":430},11,[338,432,280],{"class":344},[338,434,435],{"class":348}," --from=build \u002Fapp\u002F.output .\u002F.output\n",[338,437,439,442,445,449,452,455],{"class":340,"line":438},12,[338,440,441],{"class":344},"CMD",[338,443,444],{"class":348}," [",[338,446,448],{"class":447},"s_sjI","\"node\"",[338,450,451],{"class":348},", ",[338,453,454],{"class":447},"\".output\u002Fserver\u002Findex.mjs\"",[338,456,457],{"class":348},"]\n",[220,459,460],{},"Three things make a Dockerfile build well on Kuppit:",[462,463,464,471,488],"ul",{},[465,466,467,470],"li",{},[262,468,469],{},"Order for the cache."," Copy the manifest and lockfile, install, then copy the source. The install layer is reused across builds until the lockfile changes, which is most of the difference between a two-minute build and a ten-minute one.",[465,472,473,476,477,480,481,451,484,487],{},[262,474,475],{},"Keep the context small."," A ",[224,478,479],{},".dockerignore"," with ",[224,482,483],{},"node_modules",[224,485,486],{},".git"," and build output keeps the context Kuppit uploads to what the build needs.",[465,489,490,493,494,496],{},[262,491,492],{},"No secrets in the image."," Build arguments and ",[224,495,424],{}," lines are baked into layers. Anything sensitive comes from the service's variables at runtime.",[220,498,499],{},"Variables reach the running container, not the build. A value the build itself needs must be in the repository.",[233,501,503],{"id":502},"deploy","Deploy",[220,505,506,507,510,511,513,514,517,518,521,522,327],{},"Follow the ",[508,509,13],"a",{"href":14},": install the GitHub App, choose the repository and branch, confirm the proposal with ",[262,512,226],{}," as its strategy, and choose ",[262,515,516],{},"Deploy analyzed commit",". The ",[262,519,520],{},"Build"," log shows each Dockerfile step; a failing step ends the deployment with ",[262,523,524],{},"The build failed",[233,526,528],{"id":527},"configuration-and-a-database","Configuration and a database",[220,530,531,532,534,535,538,539,451,542,544,545,547,548,551,552,555],{},"The service's ",[262,533,24],{}," tab is ",[224,536,537],{},"process.env",", or its equivalent in your language, inside the container. A database is added the same way as for any service: ",[262,540,541],{},"Add resource",[262,543,129],{},", then a variable that is a ",[262,546,18],{}," to ",[224,549,550],{},"database"," → ",[224,553,554],{},"DATABASE_URL",", and a redeploy. The value is a standard PostgreSQL connection string that any client library accepts.",[233,557,559],{"id":558},"from-here","From here",[220,561,562,563,566,567,569,570,572],{},"A build that exceeds 15 minutes fails with ",[262,564,565],{},"The build ran out of time","; the cache ordering above is the usual fix. ",[508,568,55],{"href":56}," has the rest, and ",[508,571,102],{"href":103}," the limits.",[574,575,576],"style",{},"html pre.shiki code .sw1J6, html code.shiki .sw1J6{--shiki-light:#F76D47;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}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);}",{"title":334,"searchDepth":367,"depth":367,"links":578},[579,580,581,582,583],{"id":235,"depth":358,"text":236},{"id":313,"depth":358,"text":314},{"id":502,"depth":358,"text":503},{"id":527,"depth":358,"text":528},{"id":558,"depth":358,"text":559},"Any language, any runtime. Kuppit builds your Dockerfile as written, caches its layers, and routes to port 8080.","md",{},{"title":205,"description":584},{"loc":206},"ZCA9ulnVOTIDk4kdTH4gT7r7RmPz0cdJI1aySGpNyRo",[591,593],{"title":201,"path":202,"stem":203,"description":592,"children":-1},"From an Express repository to a live URL. The one requirement is that your server listens where Kuppit routes.",{"title":209,"path":210,"stem":211,"description":594,"children":-1},"A long-lived copy of Production on its own branch, with its own database, that deploys on every push to develop.",1788549620027]