Build configuration
We read your repository, work out what it is, and build a container image for it. Most repositories need no configuration; when yours does, a Dockerfile gives you full control.
How your app is detected#
Detection looks at the files in your app’s root directory. The first match wins, in this order:
| Order | If the root contains | Built as |
|---|---|---|
| 1 | Dockerfile | Your Dockerfile, exactly as written. See below. |
| 2 | hugo.toml, hugo.yaml or hugo.json | Hugo, built with hugo --minify and served as a static site |
| 3 | composer.json | PHP: Laravel, Symfony, or plain PHP |
| 4 | package.json | A Node framework — see Node frameworks |
| 5 | requirements.txt, pyproject.toml or Pipfile | Python: Django, FastAPI, Flask, or a script |
| 6 | Cargo.toml | Rust |
| 7 | go.mod | Go |
| 8 | Gemfile | Ruby, or Rails |
| 9 | pom.xml or build.gradle | Java, with Maven or Gradle |
| 10 | index.html | A static site, served as it is |
If nothing matches, the deployment fails with framework_undetected. Add a Dockerfile to build anything else.
Node frameworks
For a package.json, the framework is read from your dependencies, in this order. The build step runs your build script, if you have one.
| Dependency | Framework | Runs as |
|---|---|---|
next | Next.js | A server, with next start. See below for output modes. |
nuxt | Nuxt | A server |
@remix-run/node | Remix | A server |
@sveltejs/kit | SvelteKit | A server |
gatsby | Gatsby | A static site |
@docusaurus/core | Docusaurus | A static site |
astro | Astro | A server if output is server or hybrid, otherwise a static site |
@angular/core | Angular | A static site |
vite | Vite (React or Vue) | A static site |
react-scripts | Create React App | A static site |
express, fastify, koa, @nestjs/core | Node server | Your start:prod or start script |
| anything else, with a start script | Node | Your start script |
Next.js output modes
- Default: runs
next start. output: 'standalone': runs the generatedserver.js, with.next/staticandpubliccopied alongside it. Smaller and faster to start.output: 'export': served as a static site fromout/. There is no server.
The port your app listens on#
Your app receives its port in the PORT environment variable. Listen on it, on all interfaces (0.0.0.0), not only localhost.
| Runtime | PORT |
|---|---|
| Node, Ruby | 3000 |
| Python | 8000 |
| Go, Rust, Java, PHP, static sites | 8080 |
| Your own Dockerfile | The last numeric EXPOSE line, or 3000 if there is none |
A deployment is ready when something accepts connections on that port. If nothing does within four minutes, it fails with rollout_failed.
Node.js#
Version
Supported major versions are 18, 20, 22 and 24. The default is 22. Set engines.node in package.json to choose another; ranges such as >=20 and ^18 are understood, and the newest supported version that satisfies yours is used. A .nvmrc is read only when engines.node is absent.
{
"engines": { "node": "20.x" }
}Package manager
Chosen from your lockfile:
| Lockfile | Install command |
|---|---|
pnpm-lock.yaml | pnpm install --frozen-lockfile |
yarn.lock | yarn install --immutable |
bun.lock or bun.lockb | bun install --frozen-lockfile |
package-lock.json | npm ci |
| none | npm install |
Development dependencies are installed, so your build tools are available. Workspaces and monorepos are supported; see Root directory.
Other runtimes#
| Runtime | Version | What we run |
|---|---|---|
| Python | 3.12 | Installs requirements.txt, or the project from pyproject.toml. Django runs under gunicorn, FastAPI under uvicorn, Flask under gunicorn; otherwise python main.py. One of manage.py, app.py, main.py, wsgi.py, asgi.py, application.py, server.py or run.py must be in the root directory. |
| Go | 1.23 | Builds the first main package in the module and runs it. |
| Rust | stable | Runs cargo build --release --locked and starts the binary it produces. |
| Ruby | 3.3 | Rails runs rails server; otherwise ruby app.rb. |
| PHP | 8.3 | Apache, serving public/ if public/index.php exists, otherwise the root. Dependencies installed with Composer. |
| Java | 21 | Builds with Maven or Gradle, skipping tests, and runs the jar. |
These are the defaults we generate. To use a different version or command, bring your own Dockerfile.
Your own Dockerfile#
If the root directory contains a file named exactly Dockerfile, it is built as written and nothing is detected. This is how to deploy any language, version or start command we do not generate.
Environment variables reach your Dockerfile build in two ways; see Environment variables.
Root directory#
For a monorepo, set Settings → Source → Root directory to the folder that contains the app, such as apps/web. Detection, the build and the start command all run from there. The whole repository is still fetched, so the build can use shared code from other folders when your tooling supports it.
If the app brings its own Dockerfile and needs files from outside its folder — a shared package, a lockfile at the repository root — turn on Include files outside <your root directory> under Settings → Build. The build then runs from the top of the repository, using the Dockerfile in your root directory. It has no effect on Dockerfiles we generate.
Build resources#
Each build runs on its own machine with 2 vCPUs and 4 GB of memory, which is discarded when the build ends. Nothing is shared between builds, so every build installs dependencies from scratch. A build that runs longer than 20 minutes is stopped and fails with build_timeout.
Something missing or wrong on this page? Tell us, and quote the page title.