Build types
Every application has one of three build types. You pick it when you create the app, and you can change it later under Source and build → Edit settings on the app page. The change applies from the next deployment.
How Shiplon suggests a build type
Section titled “How Shiplon suggests a build type”After you choose a repository and branch, Shiplon reads the app’s folder (the repository root, or the root directory you set) and pre-selects a type with the reason it chose it. The first rule that matches wins:
| Shiplon finds | Suggestion | Also filled in |
|---|---|---|
A Dockerfile |
Dockerfile | |
package.json with a start script |
Node.js server | Build command, if there’s a build script |
package.json with only a build script |
Static site (built first) | Build command, and output folder build for Create React App |
Anything else, for example index.html |
Static site (served as it is) |
The suggestion never overrides a choice you’ve made. If you change the root directory, Shiplon checks that folder again.
The package manager follows your lockfile, so the suggested build command is pnpm run build, yarn run build or npm run build to match.
Static site
Section titled “Static site”For plain HTML and for tools whose build produces static files.
- Without a build command, the files in the output directory (default: the app’s folder itself) are served as they are. Nothing is installed.
- With a build command, Shiplon installs dependencies, runs your build in Node.js 22, then serves the output directory. The usual folders are
distfor Vite and Astro,buildfor Create React App, andpublicfor Hugo.
Files are served by nginx. A request for a path that doesn’t exist gets a 404.
Node.js server
Section titled “Node.js server”For apps that start their own server: Next.js with next start, Express, Fastify, NestJS and similar.
- Install: your lockfile decides the tool.
pnpm-lock.yaml→pnpm install --frozen-lockfile,yarn.lock→yarn install --frozen-lockfile,package-lock.json→npm ci, onlypackage.json→npm install. You can set your own Install command. - Build: runs your Build command, if you set one, for example
npm run build. - Start: runs the Start command, default
npm start.
Your server must listen on 0.0.0.0 (not localhost) and on the app’s Port (default 3000). Shiplon also sets the PORT environment variable to that port, so the most portable code is:
const port = process.env.PORT || 3000;app.listen(port, "0.0.0.0");Apps build and run on Node.js 22.
Dockerfile
Section titled “Dockerfile”Shiplon builds the Dockerfile in your app’s folder as it is and runs the image. Use it for any language or setup the other two types don’t cover. Your image must:
- listen on
0.0.0.0on the app’s Port; thePORTenvironment variable is set to it; - run as a non-root user, given by number, for example
USER 10001. Images that run as root, or set their user by name (USER node), are refused, because Shiplon can’t verify a name is non-root. The official Node.js image’snodeuser isUSER 1000.
A minimal example for a Node.js app:
FROM node:22-alpineWORKDIR /appRUN chown 1000:1000 /appUSER 1000COPY --chown=1000:1000 . .RUN npm ci && npm run buildENV PORT=3000EXPOSE 3000CMD ["npm", "start"]Using environment variables while building
Section titled “Using environment variables while building”Environment variables are not passed to docker build as build arguments, so they can’t leak into image layers. If a build step needs them, for example to download a private package, mount them as a build secret in that step:
RUN --mount=type=secret,id=appenv,required=false \ set -a; [ ! -f /run/secrets/appenv ] || . /run/secrets/appenv; set +a; \ npm ci && npm run buildAt runtime, every variable is set in the container’s environment as usual.
Which one should I choose?
Section titled “Which one should I choose?”- A site with no server code (marketing site, docs, a React or Vue app talking to an external API): Static site. It’s the fastest to build and uses the least memory.
- A JavaScript app with a server (API, Next.js with server rendering): Node.js server.
- Anything else, or you need system packages, another runtime version or full control: Dockerfile.