Skip to content

Builds

Every deployment of a Git-backed site starts with a build. Falak builds once per deployment, on a builder, and ships the result to every server. Your app servers never compile code, install Composer packages or run npm install.

Builder How you get it Build modes
Control plane builder The builder service of every installation (falak-builder serve, name control-plane) native only by default (FALAK_LOCAL_BUILDER_MODES=native)
Builder server A server of type builder. falak-builder is installed automatically when it finishes provisioning. native and docker (with Docker installed)
External builder Created under Settings → Builders; run falak-builder serve --url … --token … anywhere Organization-scoped

A builder long-polls GET /api/internal/builds/next and takes the next job it is eligible for (organization and build mode). See Builders.

Mode API value Output Used by
Native native A deterministic tar.gz release (for example vendor/, node_modules/, built assets) PHP, Node, Bun, Deno and static sites (default)
Docker docker An image pushed to Falak’s registry: <registry>/<namespace>/<site-slug>:<build-id> Docker and Compose sites
On server on-server Not supported yet: deployments fail fast with a clear error

The builder inspects the repository root and picks the first match:

Found Stack Steps
composer.json PHP (Laravel when laravel/framework is required and artisan exists) composer install --no-dev --optimize-autoloader --no-interaction --prefer-dist --no-progress; then, if package.json has a build script, install JS dependencies and run build with NODE_ENV=production. node_modules is not shipped.
deno.json / deno.jsonc Deno deno install (--frozen with deno.lock); deno task build if defined
package.json Node or Bun Install, build script if present, prune dev dependencies
index.html Static none
public/index.html Static (output public) none

Package manager (Node): packageManager in package.json, else bun.lock/bun.lockb → bun, pnpm-lock.yaml → pnpm, yarn.lock → yarn, else npm.

Package manager Install Prune
npm npm ci --include=dev (with a lockfile), else npm install --include=dev npm prune --omit=dev
pnpm pnpm install --frozen-lockfile pnpm prune --prod
yarn classic yarn install --frozen-lockfile yarn install --production …
yarn berry (.yarnrc.yml) yarn install --immutable (keeps all dependencies)
bun bun install (--frozen-lockfile with a lockfile) bun install --production

Versions are read from your project: PHP from config.platform.php or require.php in composer.json; Node from your version files or engines; Bun from packageManager.

Static output: Vite (dist), Create React App (build) and Astro (dist, unless @astrojs/node is installed) produce static sites when there is no start script. With the static runtime, the first existing of dist, build, out, public is used.

When Railpack is installed on the builder, its detection enriches the plan (versions, start command).

Set these site variables to replace the detected steps (both run with sh -c):

Variable Replaces
FALAK_INSTALL_COMMAND The dependency install step
FALAK_BUILD_COMMAND The build step
Site variables
FALAK_INSTALL_COMMAND=pnpm install --frozen-lockfile --filter web...
FALAK_BUILD_COMMAND=pnpm --filter web build

See Monorepos and build commands.

Builds do not see all your site variables. They see:

  • variables whose names start with a public front-end prefix: VITE_, NEXT_PUBLIC_, NUXT_PUBLIC_, PUBLIC_, REACT_APP_;
  • variables you expose to the deploy script (a per-variable opt-in in the Variables editor), for other build-time settings such as Astro’s SITE_URL.

${{ service.KEY }} references in those variables are resolved before the build.

.git, .DS_Store, /.env, /.env.*.local, /.falak-build, Thumbs.db and /storage/logs/* (except storage/logs/.gitignore) are never shipped. PHP builds also exclude /node_modules.

For docker mode, the builder chooses a Dockerfile in this order:

  1. The Dockerfile path set on the site.
  2. Dockerfile in the repository root.
  3. A Railpack build plan, when Railpack is available.
  4. A Dockerfile generated for the detected stack (printed in the build log).

Images are built with BuildKit and pushed to the built-in registry. Images no build or release needs any more are deleted daily, and a weekly garbage collection frees their layers.

Setting Default Variable
Build timeout 1800 s FALAK_BUILD_TIMEOUT
Queued build expires if no builder takes it 3600 s FALAK_BUILD_QUEUE_TTL
Running build fails without a builder heartbeat 90 s FALAK_BUILD_HEARTBEAT_TIMEOUT
Artifacts kept per site 10 FALAK_ARTIFACTS_KEEP
Artifact maximum age 90 days FALAK_ARTIFACTS_MAX_AGE_DAYS
Maximum artifact size 4 GiB FALAK_ARTIFACTS_MAX_BYTES
Build log retention 30 days

Package-manager and BuildKit caches persist in the builder’s cache directory between builds. Clone credentials are fetched when a job is handed out and never stored.

If a builder restarts mid-build, the build fails with “Builder <name> restarted during the build.” instead of hanging.