Deploy a Laravel and Vue app

The production build Laravel Cloud documents, the Inertia SSR bundle, the queue, and the public/hot file that breaks a live site.

For your AI agent

Copies a prompt. Paste it into the AI agent you already have open.

Read https://laravel-vuejs.space/deploy-laravel-vue.md
Ship the Vue starter kit without leaving the dev server file on the machine.
Do not put storage:link or queue:restart in the Cloud deploy command.
Do not deploy public/hot.
Do not run composer dev:ssr. The kit has no such script.
Show the diff. Do not commit.

Next: Server-render a Laravel and Vue Inertia app

On this page · 9 sections
  1. The build
  2. Do not deploy the dev server
  3. Server-side rendering
  4. The queue
  5. A VPS in one paragraph
  6. Recap
  7. FAQ
  8. Next steps
  9. Sources

Your app works locally, you deploy, and every page is a blank screen trying to load JavaScript from localhost. That’s one stray file. Here is the whole deploy for a Laravel + Vue app, in order, with the traps marked.

TL;DR

  • Build: composer install --no-dev, npm ci, npm run build (or build:ssr), php artisan optimize.
  • Never deploy public/hot. Set every VITE_* before the build.
  • php artisan migrate --force; skip storage:link on Laravel Cloud.
  • Production needs a supervised queue worker (and an SSR process if you use SSR).

What you'll learn

  • The build commands for every release
  • What must never reach the server
  • How SSR, the queue and migrations fit in

Who it's for: Developers shipping a Laravel + Vue starter kit app

Applies to: Laravel 13 · Vue starter kit · Vite · Laravel Cloud · VPS

A Laravel and Vue app is one PHP app plus a Vite build. The mistake that takes sites down is shipping public/hot, which tells Laravel to load assets from the dev server. The rest is a short list.

This assumes the Vue starter kit. A separate SPA from the Sanctum guide is two deploys: this one for the API, and the SPA host for the static files.

  1. Build PHP and the assets.
  2. Cache config, routes and views with optimize.
  3. Migrate with --force.
  4. Keep public/hot off the server.
  5. Run the queue (and SSR) as long-lived processes.

The build#

Laravel Cloud’s deploy guide uses this on every release:

bash
composer install --no-dev
npm ci --audit false
npm run build
php artisan optimize

npm run build writes public/build and a manifest. Blade’s @vite reads that manifest. php artisan optimize caches config, routes, and views into the release. Run it during the build, not after the release is already taking traffic.

Gotcha: optimize freezes the environment

APP_ENV must be production and APP_DEBUG must be false before optimize. A cached config file keeps whatever was in the environment at that moment. Change a key later and you need another php artisan optimize, or php artisan optimize:clear if you are debugging.

Then:

bash
php artisan migrate --force

Heads up: storage:link on Cloud vs a VPS

--force is required when APP_ENV is production. Do not add storage:link to a Cloud deploy. Cloud’s disk resets on every deploy, so the symlink does not survive, and Cloud’s own guide says to skip that command. User uploads on Cloud belong in the object storage bucket Cloud attaches. On a VPS, storage:link is once per machine when that machine serves the public disk from the file upload guide.

Do not deploy the dev server#

Gotcha: public/hot

Vite writes public/hot while npm run dev is running. If that file is on the server, every page tries to load JavaScript from your laptop’s URL. Delete it. Do not commit it. The same goes for node_modules: install them in the build, then you only need the compiled files at runtime.

A pre-deploy check

bash
test -f public/hot && echo "remove public/hot" || echo "ok: no public/hot"
test -f public/build/manifest.json && echo "ok: manifest built"

Set every VITE_* variable before npm run build. Vite inlines them. A Reverb key added after the build does not show up until you build again. See the Reverb guide.

Server-side rendering#

The Vue starter kit can render the first HTML on the server. Laravel Cloud says to swap the asset command when you want that:

bash
npm run build:ssr

Use it instead of npm run build when those pages need server HTML. npm run build writes only the browser bundle and leaves bootstrap/ssr stale. Locally, composer run dev already server-renders. The current starter kit has no dev:ssr script. In production the SSR process has to stay up, the same way a queue worker stays up. Laravel Cloud and Forge both know how to keep that process running. On a VPS you supervise php artisan inertia:start-ssr yourself.

SSR is how a public Inertia page has HTML for a crawler before Vue boots. A logged-in app can ship the client bundle only. Pick that in the stack guide, not at the end of a deploy.

The queue#

Mail, broadcasts, and any ShouldQueue listener do nothing without a worker:

bash
php artisan queue:work

composer run dev started one on your machine. Production does not.

Laravel CloudVPS
Queue workerManaged, restarted on deploySupervise queue:work; run queue:restart after deploy
SSR processManagedSupervise php artisan inertia:start-ssr
storage:linkSkip (disk resets)Once per machine

On a VPS, supervise php artisan queue:work and signal it with queue:restart after each deploy so it loads the new code. Cloud restarts its workers itself, so queue:restart is not a Cloud deploy command.

If you broadcast with Reverb, that is a second long-running process. The asset build does not include it.

A VPS in one paragraph#

Point the web server at the public directory. The front controller is public/index.php. PHP 8.3 or newer, the extensions in the requirements, and a database. Put public/build on disk, keep public/hot off disk, run migrations, and supervise the queue. That is the same app Cloud builds. The host is the part you are now operating yourself.

Recap#

  • One PHP app plus one Vite build.
  • optimize after the environment is final.
  • No public/hot, no node_modules at runtime.
  • Queue and SSR are processes you keep running.

FAQ#

Why does my deployed Laravel site load assets from localhost?

A public/hot file was deployed. Delete it and keep it out of git.

Do I need to run php artisan optimize on every deploy?

Yes, during the build, after APP_ENV and APP_DEBUG are final. Re-run it after changing environment keys.

Should I run storage:link on Laravel Cloud?

No. Cloud’s disk resets on every deploy; use the attached object storage bucket for uploads.

Why does my SSR HTML stay old after deploy?

npm run build does not refresh bootstrap/ssr. Use npm run build:ssr and restart the SSR process.

Next steps#

Sources#

Found this useful?

Ask questions, share what you built.

Join thousands of Laravel and Vue developers in our Facebook group, or get new posts in your Telegram feed. Sharing this article helps too.

Keep reading

Newsletter

Get the best of Laravel & Vue, once a month.

One short email with new guides, release notes worth reading and hand-picked community links. No spam, unsubscribe any time.