ADMN
Laravel API + Nuxt 3

Preview environments for a decoupled Laravel + Nuxt stack

Two services, one environment. Every pull request boots your Laravel API and a separate Nuxt 3 SSR frontend on the same managed VPS — migrated, seeded, and wired to each other with CORS, Sanctum cookies and an auto-injected API base URL. One HTTPS link, torn down clean when the PR closes.

  • Nitro SSR or static
  • Sanctum + CORS wired
  • Seeded MySQL / Postgres
One environment, two services

An API and a frontend, provisioned together and wired

A decoupled stack is two deployments, not one. We bring up both inside a single environment and connect them, so the frontend you review is always pointed at the matching API.

Service A · PHP

Laravel API

  • composer install, real web server
  • migrate --seed
  • Isolated MySQL / Postgres
  • Redis, queue:work + scheduler
api.acme-feed.admn.cloud
Service B · Node

Nuxt 3 frontend

  • npm ci then nuxt build
  • Nitro Node SSR process
  • runtimeConfig.public API base
  • Stateless — talks HTTP to the API
acme-feed.admn.cloud
Why decoupled is the hardest to preview

Two deploys that have to agree about each other

A single-origin app is one box. A decoupled Laravel + Nuxt stack is two services that must line up on URLs, CORS allow-lists and cookie domains — and every one of those is easy to get subtly wrong by hand, per branch.

The API base goes stale

The Nuxt build bakes in an API URL that points at someone’s laptop or last week’s box, so the reviewed frontend talks to the wrong backend.

CORS and cookies fight you

Cross-origin requests get blocked, Sanctum cookies don’t stick because SESSION_DOMAIN is off, and login silently fails only in the preview.

Two deploys, one chance to drift

You stand the API up, then the frontend, then patch env by hand. Miss a variable and SSR renders one thing while the browser fetches another.

Everything, both halves

What each Laravel + Nuxt preview includes

Both services and their backing infrastructure boot on the same VPS, connected and served behind one HTTPS hostname.

Laravel API service
PHP + ComposerYour PHP version, composer install, served by a real web server.
Isolated databaseMySQL or Postgres per environment, migrate + seeders on boot.
Redis, queues, schedulerCache and sessions, a queue:work worker and the scheduler running.
Nuxt 3 frontend service
Nitro SSR servernuxt build then a long-lived Node process — real server-side rendering.
Auto-wired API baseNUXT_PUBLIC_API_BASE set to this environment’s API URL before build.
Sanctum + CORS readyStateful domains, CORS allow-list and cookie domain configured across both origins.
Both builds, automated

Two services, declared once and run on every push

You give each service its install and build commands. We run them in clean containers, bring the API up first, then build the Nuxt app against its live URL.

# service A — laravel api (brought up first)
composer install --optimize-autoloader
php artisan migrate --seed   # isolated DB, realistic data
php artisan queue:work & php artisan schedule:work
✓ api https://api.acme-feed.admn.cloud

# service B — nuxt 3 frontend, wired to the api above
export NUXT_PUBLIC_API_BASE=https://api.acme-feed.admn.cloud
npm ci && nuxt build              # nitro node server output
node .output/server/index.mjs       # long-lived SSR process
✓ web https://acme-feed.admn.cloud
How it works

From two branches to one shareable URL

  1. 01

    Define both services

    Point ADMN at your API and Nuxt app — one monorepo or two repos — and declare each service’s build commands and database template once.

  2. 02

    Pick the branches

    Choose a branch (or a PR of each). We provision the VPS, bring the API up with a seeded database, then build Nuxt against its live API URL.

  3. 03

    Share one URL

    A real HTTPS frontend talking to its matching API — CORS and Sanctum already working. Renew the lease to keep it, or let it expire and tear down clean.

Questions

Decoupled Laravel + Nuxt previews, answered

How do the two services find each other?

We provision both services inside the same environment and wire them automatically. The Laravel API comes up on its own in-environment HTTPS URL, and that URL is injected into the Nuxt service as NUXT_PUBLIC_API_BASE before `nuxt build` runs. You never hard-code an API host or paste URLs between deploys — the frontend always points at the matching API for that exact branch.

Does Sanctum SPA cookie authentication work across the two origins?

Yes. Because the API and frontend live in the same environment, we configure Sanctum and CORS for you: SANCTUM_STATEFUL_DOMAINS and SESSION_DOMAIN cover the frontend origin, the CORS allow-list permits it with credentials, and SESSION_DOMAIN is set so the auth cookie is shared. The `/sanctum/csrf-cookie` handshake and credentialed XHR/fetch calls work exactly like production.

Does Nuxt run as a real SSR Node server, or static?

Both are supported. By default we run `nuxt build` and start the Nitro Node server as a long-lived process, so server-side rendering, server routes and runtimeConfig all behave like production. If your app is `nuxt generate` (static / SPA), we serve the prerendered output instead — you pick per project.

One repo or two?

Either. A monorepo with the API and Nuxt app in separate directories works — you point each service at its subdirectory and declare its build commands. Two completely separate repositories also work: a preview environment can pin a branch of each, so a coordinated API + frontend change previews together.

Where does the database live?

With the API. Each environment gets its own isolated MySQL or PostgreSQL database attached to the Laravel service, migrated with `php artisan migrate` and seeded on first boot. Redis is provisioned alongside it for cache, sessions and queues. The Nuxt service is stateless — it only talks to the API over HTTP.

What happens to runtimeConfig and client-side API calls?

NUXT_PUBLIC_API_BASE is a public runtime key, so it is available both during SSR (server-side fetches from the Nitro process) and in the browser bundle (client-side calls after hydration). We set it once at build time to the environment’s API URL, so server and client agree on where the API is — no env drift between the two halves of a render.

Preview your API and Nuxt frontend together

Connect GitHub and get both services provisioned, wired and seeded for every branch — one HTTPS URL, destroyed without a trace.