Skip to main content

How Builds Work

LaraKube CLI offers three production deploy paths. They share the same pre-build steps (Composer, Node, Wayfinder) but differ in where the Docker image is built, where npm run build happens, and where VITE environment variables come from.


The Three Paths at a Glance​

Stepbundle:build + bundle:installcloud:deploy (manual)GitHub Actions
composer installhost (via dev pod)host (via dev pod)GHA runner
npm installhost (via dev pod)host (via dev pod)GHA runner
wayfinder:generatehost (via dev pod)host (via dev pod)GHA runner
npm run buildDocker assets stageDocker assets stageDocker assets stage
VITE vars source.env.{env} + .larakube.json (mounted as BuildKit secret).env.{env} + .larakube.json (mounted as BuildKit secret).env (decoded from GHA secret, VITE_* appended)
Image destinationsaved to .tar in bundleSSH side-load or registry pushregistry push (GHCR / Docker Hub)
kubectl applyon the air-gapped serverfrom your machinefrom the GHA runner

The most important row is npm run build. In all three paths it runs inside Docker — never on the developer's machine. That means:

  • Your local public/build/ is never overwritten by a deploy.
  • The correct per-environment hostname (e.g. https://staging.myapp.com) is always baked in, not whatever happens to be in your local .env.

The Build Pipeline in Detail​


Why npm run build Is Inside Docker​

Vite bakes VITE_* environment variables into the compiled JS at build time. They cannot be changed at runtime. If npm run build runs on your machine:

  • It reads your local .env — which has dev values like localhost or .kube hostnames.
  • Those wrong values get frozen into the image and shipped to production.

By moving the build into Docker, LaraKube CLI mounts your .env.{environment} file as a BuildKit secret (--secret id=dotenv,src=.env.staging). Vite reads it at build time to get the correct VITE_* values. The secret is never baked into any image layer — not in the assets stage, not in deploy.

LaraKube CLI appends the VITE_* values it derives from your .larakube.json config (the hostnames you set when running larakube env production or larakube env airgap --offline) to the secret before the build, so you never have to add them manually to your .env files.


Wayfinder and PHP in the Assets Stage​

Wayfinder generates TypeScript route definitions from your PHP routes via php artisan wayfinder:generate. The @laravel/vite-plugin-wayfinder Vite plugin also re-calls this command during every npm run build.

Because the assets stage is built FROM base (the same PHP image your app uses), PHP is available — Wayfinder's Vite plugin works without any workarounds. The pre-deploy step on the host still runs wayfinder:generate first; the Docker stage may re-run it cleanly as part of the Vite build.


REVERB_APP_KEY for Air-Gapped Bundles​

For bundle builds with Reverb, REVERB_APP_KEY must be known at build time (so it can be baked as VITE_REVERB_APP_KEY) and at install time (so the server's Reverb config matches). LaraKube CLI handles this automatically:

  1. bundle:build generates a random REVERB_APP_KEY and stores it in bundle.json.
  2. The key is written into the BuildKit secret (the augmented .env.{environment} file) so Vite bakes VITE_REVERB_APP_KEY into the compiled JS without exposing it in any image layer.
  3. bundle:install reads the key from bundle.json and uses it when writing the Kubernetes secrets — so the baked JS and the runtime server are always in sync.

For cloud:deploy and GitHub Actions, REVERB_APP_KEY comes from your .env / GHA secrets and is injected at deploy time.


Keeping Your Dockerfile Up to Date​

The assets stage was introduced in v0.18.41. If your project was scaffolded before that version, run:

larakube heal

This regenerates Dockerfile.php with the new stage. Your existing cloud:deploy and bundle:build will pick it up on the next run.