Builds
Push code; get a container. Here is exactly what happens in between.
Build strategy
Buildfyio picks the first strategy that applies:
| Priority | Strategy | When |
|---|---|---|
| 1 | Dockerfile in your app directory | You opted into full control — we build it verbatim and never override it. |
| 2 | Workspace build | The app is a pnpm / yarn / npm workspace member — installed and built from the repository root, like locally. |
| 3 | Automatic detection (Nixpacks) | 25+ runtimes: package manager, build and start commands detected from the repo. |
| 4 | Framework template | Fallback if automatic detection cannot build — a curated per-framework image. |
Build-time environment
Every environment variable you define reaches the build. Non-secret values are injected as plain build environment; secret-marked values are mounted with BuildKit secret mounts, so they are available to the build process (a Next.js prerender reading an API key, for instance) without ever being written into an image layer. Rotating a secret automatically invalidates the build cache for that step.
*_SECRET, *_API_KEY, *_PASSWORD, *_SERVICE_KEY, *_PRIVATE_KEY, …) are treated as secrets automatically, even if you did not mark them.Caching
Layer cache is kept in a private registry per project. In practice: a rebuild with unchanged dependencies skips the install step entirely — cache-warm rebuilds typically run in under a minute.
Ports
The detected port comes from your framework (3000 for Next.js, 4321 for Astro, …). If your start command names an explicit port — next start --port 3002, -p 8080, PORT=5000 node server.js — that port wins everywhere: health checks, routing, and the container contract. Your app should listen on 0.0.0.0, not localhost.
Framework notes
Astro
- Static Astro publishes straight to the edge — no container, instant serves.
- SSR Astro (an adapter in
astro.config) builds and runs as a container. - Repos configured with
@astrojs/vercelrun unchanged: the build swaps in a runnable server adapter automatically. Your repository is never modified.
Prisma
prisma generate runs automatically when a schema is present — including in pnpm workspaces where package postinstall scripts are blocked by default.
devDependencies
Build tooling that lives in devDependencies (Tailwind, Vite plugins, type checkers) is always installed at build time — production pruning happens after the build, not before it.
Bring your own Dockerfile
# Detected automatically when apps/api/Dockerfile exists FROM node:20-alpine WORKDIR /app COPY . . RUN npm ci && npm run build EXPOSE 3000 CMD ["node", "dist/main.js"]