Livewire 3 on Vercel

How to setup and deploy a Laravel and Livewire project on Vercel


At the time I’m writing this, the launch of Laravel Cloud is just around the corner, however one of the features I love about Vercel is their password protection and preview comments. Which is really useful when you want to get some feedback from a client.

So I thought I’d write a quick guide to get a Livewire 3 project up and running on Vercel.

Let’s start by installing Laravel and Breeze, but this should work for Jetstream or any other project:

laravel new vercel-example

Installing Livewire

After that you should be able to see the website running:

cd vercel-example
php artisan serve

Laravel Breeze welcome page

Now most of these steps follow this guide on how to Deploy Laravel 11 on Vercel with some slight modifications to allow Livewire to run.

First add an api/index.php file to the root of your project with the following:

<?php

require __DIR__ . '/../public/index.php';

Then create a vercel.json file in the root of your project:

{
  "version": 2,
  "outputDirectory": "public",
  "functions": {
    "api/*.php": {
      "runtime": "vercel-php@0.7.3"
    }
  },
  "routes": [
    {
      "src": "/(.*\\.(?:css|js|png|jpg|jpeg|gif|svg|ico|ttf|woff|woff2|eot|otf|webp|avif|txt))$",
      "dest": "/public/$1"
    },
    {
      "src": "/(.*)",
      "dest": "/api/index.php"
    }
  ]
}

Now, when someone tries to access the website on Vercel it’ll use the new api/index.php file we created:

{
  "src": "/(.*)",
  "dest": "/api/index.php"
}

Which simply tells Vercel to run the Laravel app from public/index.php

<?php

require __DIR__ . "/../public/index.php";

And then any other assets will be served from the public folder:

{
  "src": "/(.*\\.(?:css|js|png|jpg|jpeg|gif|svg|ico|ttf|woff|woff2|eot|otf|webp|avif|txt))$",
  "dest": "/public/$1"
},

One problem we have is that when you load a Livewire 3 project it requests the livewire.js file at livewire/livewire.js which is served dynamically. To overcome this we can publish the livewire assets:

php artisan livewire:publish --assets

Now our Livewire app will request the livewire.js file from /public/vendor/livewire/livewire.js and our Vercel app can read it correctly.

You can also update the composer.json file to keep these files up to date automatically:

{
    "scripts": {
        "post-update-cmd": [
            // Other scripts
            "@php artisan vendor:publish --tag=livewire:assets --ansi --force"
        ]
    }
}

If you’re using Flux UI there’s current no way to publish the assets (yet) but we can get Vercel to handle them with PHP instead.

Let’s add that route before we handle any other css or js files:

"routes": [
  {
    "src": "/flux/(.*)",
    "dest": "/api/index.php"
  },
  {
    "src": "/(.*\\.(?:css|js|png|jpg|jpeg|gif|svg|ico|ttf|woff|woff2|eot|otf|webp|avif|txt))$",
    "dest": "/public/$1"
  },
  {
    "src": "/(.*)",
    "dest": "/api/index.php"
  }
],

If you don’t want to publish the livewire.js files you can also just add that handler here:

{
  "src": "/livewire/(.*)",
  "dest": "/api/index.php"
},

Next let’s create a .vercelignore file and add this line to ignore our composer installs:

/vendor

Then edit the .gitignore file and ignore the vercel folder that gets generated on deploy:

.vercel

Then we need to do is set up the Trusted Proxies, so let’s edit our boostrap/app.php file:

<?php

use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up'
    )
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->trustProxies(at: '*'); // add this line
    })
    ->withExceptions(function (Exceptions $exceptions) {
        //
    })
    ->create();

The last thing we need to do is update the package.json file to specify the node engine, otherwise Vercel has problems during the build process (at the moment) loading PHP libraries like libssl.so, curl or pdo_pgsql

"engines": {
  "node": "18.x"
},

Now let’s deploy the project from our command line.

vercel

Everything should be set up correctly now so Vercel should be able to automatically deploy everything for us us.

Laravel Vercel Error on Deploy

I ran into this issue which says the filesystem is readonly, so let’s try fix that. From the vercel-php docs I found a similar Github issue that seems to be related to Livewire. So let’s update our AppServiceProvider:

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        if (config('app.vercel.enabled')) {
            $paths = [
                '/tmp/framework/sessions',
                '/tmp/framework/cache',
                '/tmp/storage/bootstrap/cache',
                '/tmp/storage/framework/cache',
                config('view.compiled'),
            ];

            foreach ($paths as $path) {
                if (! is_dir($path)) {
                    mkdir($path, 0755, true);
                }
            }
        }
    }

And then let’s update our config/app.php file to match:

/*
|--------------------------------------------------------------------------
| Ensure the livewire-tmp folder and real-time faces are being processed.
| https://github.com/vercel-community/php/issues/175
|--------------------------------------------------------------------------
*/

'vercel' => [
    'enabled' => (bool) env('VERCEL', false),
],

Now that you have access to the project dashboard on settings on Vercel, you can update the envs and add the database credentials:

VERCEL=true

APP_NAME=Laravel
APP_KEY=base64:/abc/xxxxxx
APP_URL=

DB_CONNECTION=pgsql
DATABASE_URL=postgresql://postgres.(...).supabase.com:5432/postgres
DB_HOST=abc.pooler.supabase.com
DB_DATABASE=postgres
DB_USERNAME=postgres.abc
DB_PASSWORD=aaa-bbb-ccc
DB_PORT=5432

For this example I used supabase for the database connection.

Now lets deploy the project again by running vercel in the command line and it should all be working well:

Laravel Livewire running on Vercel

I can even register and login to the Laravel Breeze dashboard

Laravel Breeze Dashboard

When I use Vercel it’s mostly because of the preview comments feature, so I like to add a welcome screen on the main branch and then run the project from a staging branch.

So at this point I would create a staging branch and then push a welcome screen to the main branch.

And if you run into any problems, you can update the APP_DEBUG env variable to true in the vercel.json file so you can debug any errors.

Vercel Preview Comments

The deployments are working successfully when you deploy manually, and should work well if you connect Vercel to Git… unless you have Flux UI installed.

Flux UI requires an auth.json file which needs to be generated during the build step:

composer config http-basic.composer.fluxui.dev "${FLUX_USERNAME}" "${FLUX_LICENSE_KEY}"