With Automatic as the build type, HCode works out how to install, build and start your app from the files in your repository. You don't need a Dockerfile. This is the default for new projects unless HCode finds a Dockerfile.
What HCode recognises
When you create a project from GitHub, HCode reads the repository's manifests and proposes a plan. These are the setups it recognises, and the start command it suggests:
| Your repository has | Detected as | Suggested start command |
|---|---|---|
package.json with next |
Next.js | your start script, or next start |
svelte.config.js or @sveltejs/kit |
SvelteKit | your start script, or node build |
package.json with nuxt |
Nuxt | your start script, or node .output/server/index.mjs |
package.json with @nestjs/core |
NestJS | your start script, or node dist/main.js |
express, fastify, koa or @hapi/hapi |
Node.js server | your start script, or node <file> for main, index.js, server.js or app.js when the file exists |
vite, react-scripts or astro, and no server framework |
Static site | none, the output is served as files |
manage.py or django in your Python manifest |
Django | none; migrations run and gunicorn serves the app when it starts |
fastapi |
FastAPI | uvicorn main:app --host 0.0.0.0 --port $PORT when main.py exists |
flask and app.py |
Flask | gunicorn app:app --bind 0.0.0.0:$PORT |
go.mod |
Go | none, the compiled binary runs |
Gemfile with rails |
Ruby on Rails | bundle exec rails server -b 0.0.0.0 -p $PORT |
composer.json |
PHP | none |
index.html at the root and nothing else |
Static site | none |
When nothing more specific applies, a start script in package.json is suggested as npm start. A Procfile with a web: line wins over any suggestion: the build starts that process. Python manifests are requirements.txt, pyproject.toml or Pipfile, and Poetry is recognised.
Java projects built with Maven or Gradle also build, though the plan step doesn't name them. Bun projects with a bun.lock or bun.lockb build with the newest Bun release unless you choose a version. For language versions, see Runtime versions.
Detection only fills in the plan. Your settings decide what is built, and you can change them under Settings.
Install, build and start
Dependencies are installed from your lockfile without changing it, so production builds are reproducible. If package.json and the lockfile disagree, the build fails rather than quietly installing different versions; run your package manager locally and commit the updated lockfile. The package manager comes from the packageManager field in package.json, or from the lockfile: pnpm-lock.yaml, yarn.lock or package-lock.json.
You can override each stage under Settings, in Build configuration:
- Install command replaces the install step, for example
npm install --legacy-peer-depsfor peer dependency conflicts. It isn't used for Python and PHP projects, whose install step can't be replaced; the build log says so. - Build command replaces the build step. When
package.jsonhas abuildscript, the defaultnpm run buildruns it with your own package manager, so it works for pnpm, Yarn and Bun projects too. - Start command (optional) is what runs your app, and it overrides whatever the build produced. Leave it empty unless you need a specific command. A static site has no
nodebinary, so a command such asnode index.jsstops it from starting. - Output directory is the folder a static build writes to, such as
dist. See Static sites.
Framework preset fills those four fields for Next.js, Astro, SvelteKit, Nuxt, Remix, Vite, a Node.js server or a plain static site. For a GitHub project, Node.js (Express, Fastify…) looks up your repository's start command instead of guessing one. Save, then deploy again for a change to take effect.
Environment variables in the build
The project's environment variables are available to every build command, so a build that reads NEXT_PUBLIC_* or DATABASE_URL sees your values. They are passed as build secrets and are not written into the built image.
A few names, such as PORT and PATH, and empty or very large values are left out of the build and only reach the running app; Environment variables lists them. The build log names any variable it left out. Changing a variable changes the build, so the next deploy doesn't reuse a cached result built with the old value.
Databases during the build
HCode databases can't be reached while your app is being built, only once it runs. Run migrations and database checks from your start command, not your build command. For example:
npx prisma migrate deploy && npm start
For Django, the build runs collectstatic at the end of the build step, and migrations run when the app starts. Set DISABLE_COLLECTSTATIC=1 as an environment variable to skip collectstatic, or set your own build command, in which case HCode leaves the build step alone. A failing collectstatic prints a warning and the build carries on.
Build time
Build time counts toward your plan's build minutes, and each build has a maximum duration. Build minutes explains both. When a build fails, Build failures explains the messages HCode shows.