Build types: buildpacks vs Dockerfile
Every app has a build type. buildpacks (auto-detect via heroku-style buildpacks) is the default and works for almost everything. dockerfile uses a Dockerfile in your repo root.
The two options
| buildpacks | dockerfile | |
|---|---|---|
| Auto-detect | Yes — based on files in your repo (package.json, Gemfile, etc.) | You supply the Dockerfile |
| Build env | herokuish — same buildpacks Heroku uses | Vanilla docker build |
| Procfile | Required for non-trivial apps | Optional — CMD/ENTRYPOINT works |
| Build-time env | App config vars are exposed during build | Use ARG / build-time secrets explicitly |
| Speed | Per-deploy build on the stack | Per-deploy build on the stack OR pre-built image |
| Best for | Standard apps in standard languages | Custom toolchains, multi-stage builds, native deps |
Setting it
$ ownstack app build-type <app> buildpacks
$ ownstack app build-type <app> dockerfile
Or set "build_type" when creating the app.
Buildpack auto-detect
Herokuish picks the first matching buildpack. The standard set covers Ruby, Node, Python, Go, PHP, Java, Clojure, Scala. Order is determined by file presence:
Gemfile→ Rubypackage.json→ Node.jsrequirements.txt/Pipfile/pyproject.toml→ Pythongo.mod→ Gocomposer.json→ PHP
To override, set BUILDPACK_URL as a config var to a buildpack git URL or comma-separated list.
Example: stack a Node + Ruby app
$ ownstack config:set --app=<app> \
BUILDPACK_URL='https://github.com/heroku/heroku-buildpack-nodejs.git,https://github.com/heroku/heroku-buildpack-ruby.git'
Useful for Rails apps that need Node for asset compilation.
Dockerfile
Drop a Dockerfile in your repo root. Set build-type to dockerfile on the app. Dokku runs docker build on the stack and serves the resulting image.
Your Dockerfile must:
- End with a
CMDorENTRYPOINTthat binds to$PORT(for the web process). - Not hardcode a port in
EXPOSE— dokku ignores it and assigns dynamically. - Be self-contained: no host volumes, no networks the stack doesn't manage.
Minimal Dockerfile (Node static site)
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
CMD ["nginx", "-g", "daemon off;"]
Dokku writes a nginx.conf for you that listens on $PORT; if you supply your own, it must too.
Switching mid-life
You can switch build types on an existing app. The next deploy rebuilds from scratch with the new build type. Watch out for:
- Persistent volumes — if you mounted any, they're reattached.
- Linked services (Postgres, etc.) — unchanged.
- Config vars — unchanged.
Read next
- Git deploys
- Image deploys — pre-built Docker images.
- Procfile