Skip to main content
Laravel Cloud does not officially support monorepos yet, but you can work around this limitation with a custom build script. How you configure that script depends on what you are deploying: only the Laravel application from the monorepo, or Laravel plus a built frontend (for example, a static Nuxt site served from Laravel’s public/ directory).
Monorepo support is not officially available yet, but we are actively working on it. In the meantime, some users have had success with the workarounds below. Use them at your own risk — Laravel Cloud Support may be unable to assist with debugging custom monorepo configurations.

Choose your deployment path

  • Laravel only. Your monorepo includes a Laravel app in a subdirectory, and you want Cloud to run that app after promoting it to the repository root. Any frontend assets built with Laravel’s own tooling (for example, Vite or Laravel Mix) are compiled as part of that app after promotion; you are not copying in a separate SPA package from another directory.
  • Laravel and a separate frontend. Your monorepo has a Laravel API (or full backend) and a frontend in another directory (for example, frontend/ with Nuxt). The build script promotes Laravel to the root, builds the frontend, and copies the generated static files into Laravel’s public/ directory so one service serves both.
Both approaches use the same prerequisites in the next section.

Shared prerequisites

You need a fake composer.lock in your repository root. Copy the composer.lock file from the Laravel application subdirectory you deploy and commit it at the monorepo root. That file tells Laravel Cloud that the repository contains a Laravel application. It does not need to be kept up to date. Customize your environment’s build script in Laravel Cloud so it runs after checkout and performs the moves, installs, and builds required by your chosen path. If you add commands that use a different JavaScript toolchain than the defaults, remove or comment out the default npm steps in your build configuration so they do not conflict.

Deploying only the Laravel application

Use this approach when the only application you are shipping is the Laravel project in a subdirectory. After that directory becomes the repository root, run composer install and your usual steps (for example, npm install and npm run build for Vite or Mix assets defined in that Laravel app). If the monorepo also contains other top-level directories you are not deploying (for example, a separate frontend/ package), list only the directories you need to relocate in the script below. You can leave unused directories in the temporary folder so they are not copied into the deployment root.
# ---------------------------------
# Deploying the "laravel_app" directory
# ---------------------------------

# Step 1: Create a temporary directory
mkdir /tmp/monorepo_tmp

# Step 2: Create an array with all subdirectories
repos=("laravel_app" "go_app")

# Step 3: Move all subdirectories to the temporary directory
for item in "${repos[@]}"; do
  mv $item /tmp/monorepo_tmp/
done

# Step 4: Copy the Laravel app into the deployment root
cp -Rf /tmp/monorepo_tmp/laravel_app/. .

# Step 5: Remove the temporary directory
rm -rf /tmp/monorepo_tmp

# Step 6: Proceed with build steps
composer install --no-dev
npm install
npm run build
Notes:
  • Replace laravel_app with the name of the Laravel app directory you want to deploy.
  • If your app depends on sibling directories (such as shared packages or configuration), you will need to adjust paths manually or restructure accordingly.

Deploying Laravel and a static frontend (Nuxt)

Use this approach when you build a client-rendered frontend at deploy time and serve it from Laravel. Laravel Cloud expects a single application at the repository root; the script stashes your backend/ and frontend/ directories, promotes the Laravel app to the root, installs PHP dependencies, generates static Nuxt output, and copies that output into public/. At runtime, PHP serves the API and the static files; you do not need a Node.js server for the SPA. The directory names backend and frontend are examples. Replace them with your actual paths. The script below also removes monorepo-level files from the build working directory (for example, composer.json and composer.lock that belong to the monorepo root, not the promoted Laravel app). Some teams additionally remove .git or other files; adjust the rm list for your repository and security practices.
1

Stash backend and frontend and clear monorepo root files

Move both application directories to a temporary path, then remove files at the repository root that would conflict with copying the Laravel app into place.
2

Promote Laravel and install Composer dependencies

Copy the Laravel application into the deployment root and run composer install for production.
3

Build the frontend and copy static assets into public

Install your JavaScript tooling (this example uses Bun), install frontend dependencies, run static generation, and copy the generated files into Laravel’s public/ directory on the instance.
# ---------------------------------
# Deploying backend + frontend (Nuxt static)
# ---------------------------------

# Step 1: Create a temporary directory
mkdir /tmp/monorepo

# Step 2: Move backend and frontend to the temporary directory
repos=("backend" "frontend")

for item in "${repos[@]}"; do
  mv $item /tmp/monorepo/
done

# Step 3: Remove monorepo-level files at the repository root
rm -rf composer.lock
rm -rf composer.json
rm -rf README.md
rm -rf .gitignore
rm -rf .git
rm -rf solo.yml

# Step 4: Copy the backend into the deployment root
cp -Rf /tmp/monorepo/backend/. .

# Step 5: Install Composer dependencies
composer install --no-dev --no-interaction --prefer-dist --optimize-autoloader

# Step 6: Install Bun
npm i -g bun

# Step 7: Install frontend dependencies and generate static assets
cd /tmp/monorepo/frontend
bun install
bun run generate

# Step 8: Copy generated files into Laravel public
cp -Rf .output/public/* /var/www/html/public/

# Step 9: Remove the temporary directory
rm -rf /tmp/monorepo
The copy target /var/www/html/public/ is in the application root Laravel Cloud uses during the build. The generated index.html and assets must end up there so the web server can serve them. To install Bun (or another package manager) inside the build, see Using Yarn, PNPM, or Bun. If your environment runs default npm install and npm run build steps, align those with this script or remove them so they do not run against the wrong directory.

Application configuration for a static frontend

These details assume a statically generated Nuxt app served by Laravel, not server-side rendering in Node. Nuxt. Configure the frontend as a client-side SPA (for example, ssr: false in nuxt.config.ts) so nuxt generate (or bun run generate) produces static files. When the API and SPA share a domain in production, you can use relative URLs for API calls (for example, /api/...) instead of a separate API host in runtime config. During local development, proxy /api and /sanctum from the Nuxt dev server to your Laravel URL so routing matches production. Laravel. Add a catch-all route so unknown paths return the SPA shell while API and Sanctum routes continue to be handled by Laravel:
Route::get('/{any?}', function () {
    return response(file_get_contents(public_path('index.html')))
        ->header('Content-Type', 'text/html');
})->where('any', '^(?!api|sanctum).*$');
Authentication and CORS. Laravel Sanctum works well when the SPA and API share a domain. Configure CORS for local development (for example, your Nuxt dev origin); in production, same-origin requests avoid cross-origin issues.
This pattern serves a pre-built Nuxt site from Laravel. Nuxt SSR or a dedicated Node process for rendering is a different architecture and is not covered by this workaround.