Caleb Porzio

Easy, Free, Serverless Laravel With Vercel

Oct 2020

I’m blown away by how easy and powerful it is to get Laravel running on the popular serverless platform: Vercel.

This is not a one-to-one replacement for something more robust like Laravel Vapor, but it’s an incredibly useful tool to have in your tool-belt.

Let’s dig in.

Create A Laravel App

You can either create a new Laravel app or use an existing one. I’m going to use Laravel’s CLI tool to quickly scaffold a new app.

Configure Vercel

To go from stock install to Vercel-ready, we only need to add 3 files to this project:

Let’s walk through them one by one.

api/index.php

Create a new index.php file in a new api folder in the root directory of your Laravel app and fill it in with the following contents:

<?php

// Forward Vercel requests to normal index.php
require __DIR__ . '/../public/index.php';

Unfortunately, Vercel only allows an app’s entry-point to live inside the api directory, so we have to set up a simple script to forward to Laravel’s normal public/index.php entry-point.

.vercelignore

Add a .vercelignore file to the root of your project with the following contents:

/vendor

This will make sure we don’t upload the entirety of our vendor directory to Vercel when we deploy (We’ll set up Vercel to automatically install composer dependencies).

vercel.json

This is the meat of the set up. Create a new vercel.json config file in your root directory and paste in the following contents:

{
    "version": 2,
      "framework": null,
    "functions": {
        "api/index.php": { "runtime": "[email protected]" }
    },
    "routes": [{
        "src": "/(.*)",
        "dest": "/api/index.php"
    }],
    "env": {
        "APP_ENV": "production",
        "APP_DEBUG": "true",
        "APP_URL": "https://yourproductionurl.com",

        "APP_CONFIG_CACHE": "/tmp/config.php",
        "APP_EVENTS_CACHE": "/tmp/events.php",
        "APP_PACKAGES_CACHE": "/tmp/packages.php",
        "APP_ROUTES_CACHE": "/tmp/routes.php",
        "APP_SERVICES_CACHE": "/tmp/services.php",
        "VIEW_COMPILED_PATH": "/tmp",

        "CACHE_DRIVER": "array",
        "LOG_CHANNEL": "stderr",
        "SESSION_DRIVER": "cookie"
    }
}

Let’s walk through these settings one by one and review what’s going on. Feel free to skip these explanations.

version

"version": 2,

There are two versions of Vercel: “1” and “2”. We want the new and fancy “2”.

functions

"functions": {
    "api/index.php": { "runtime": "[email protected]" }
},

Our entire Laravel app is going to be a single serverless function (in Vercel terms).

We want the entry-point to be our newly added api/index.php, which is really just a forwarder to the main public/index.php file that would normally get hit when you visit a Laravel app from a web server.

Notice we specified a “runtime” of “vercel-php”. This is the key to whole set up. “vercel-php” is a community-built PHP runtime for Vercel functions. It does all the hard work for us like installing the proper dependencies and running composer install.

Check out the repo for more info: https://github.com/juicyfx/vercel-php

routes

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

Here we tell Vercel to forward all URIs to our newly setup server less function (our Laravel app).

Think of this like an NGINX config on a normal server.

env

"env": {
    "APP_ENV": "production",
    "APP_DEBUG": "true",
    "APP_URL": "https://bot.laravel-livewire.com",

    "APP_CONFIG_CACHE": "/tmp/config.php",
    "APP_EVENTS_CACHE": "/tmp/events.php",
    "APP_PACKAGES_CACHE": "/tmp/packages.php",
    "APP_ROUTES_CACHE": "/tmp/routes.php",
    "APP_SERVICES_CACHE": "/tmp/services.php",
    "VIEW_COMPILED_PATH": "/tmp",

    "CACHE_DRIVER": "array",
    "LOG_CHANNEL": "stderr",
    "SESSION_DRIVER": "array"
}

If you didn’t see the resemblance, this is going to be our Vercel app’s .env file.

Here you can specify any environment variables you want set. (What you would normally do in a traditional server’s .env file).

There are two important things to note:

First, you’ll notice some new env variables you don’t normally see in a .env file (APP_CONFIG_CACHE, etc…).

These are typically set by default to various places in a standard Laravel app, but because a serverless app is “state-less”, the only folder we can reliably modify at run-time is Vercel’s tmp folder.

So we’ll point all “cache/tmp” type settings here.

Second, you’ll notice there is no APP_KEY or any other sensitive environment info.

Because this file is version controlled, it’s unsafe to store sensitive keys in it. Instead we will use Vercel’s encrypted environment variables feature. We’ll get to that in a bit.

Now that you understand the configuration, let’s actually get something up and live!

Install Vercel

First we need the vercel command-line tool. Let’s install it via npm:

npm i -g vercel

Log In To Vercel

Now that it’s installed, we need to connect it to your Vercel account (or create a new one if you don’t already have one):

Run vercel login and enter your email address. Vercel will guide you through the rest. (It’s one of the best command-line login experiences out there)

Deploy

Here comes the easy part. You can deploy your app by running a single command: vercel

You can basically just hit the enter key for all the prompts because the defaults are fine for us.

Now, you can visit the provided link to view the progress of your deployment. (In our case: https://vercel.com/calebporzio/vercel-laravel/dn4r8780n)

From the deployment page, you can “Visit” the actual deployed app. (By clicking “Visit”)

And here it is in all its glory:

This is so cool to me. With 3 small files added to any Laravel project and running a simple command, you can get a free, server-less instance of your app on the internet. It’s kind of mind-blowing.

Deploying To Production

For a more robust set up. Let’s set our deployment up as “Production”.

To deploy to “Production” with Vercel, we need to push our app to a GitHub repository and link it to our Vercel account.

This way, deployments will be triggered on push automatically.

Let’s go!

Creating A GitHub Repo

Let’s head over to GitHub and create a new repository for our Laravel app.

From your profile’s homepage click the “New” button.

We’ll name it, keep the defaults and create the repo.

Now we can copy and paste the instructions from our new repo’s homepage into the command-line:

(I’m assuming you’ve already set up a Git repo locally for your project, if not run git init && git add . && git commit -m "init")

And that’s it, now let’s point Vercel to this repository.

Linking The Repo To Vercel

If you visit your new Vercel project’s main page, you’ll see a “Not Connected” link under “Git”. Click it.

You’ll be taken to a page that will prompt you to link your GitHub account with Vercel. I’ve already done this (and can’t undo and redo for this post because I have production code relying on it).

After you’ve linked your GH account, you can specify your new repo’s name and press “Save”.

Now, your app will “redeploy” every time your push to the main branch on your GitHub repo.

Your app now lives on the URL generated by Vercel. In my case, it’s vercel-laravel-three.vercel.app.

Vercel makes it easy to set up custom domains if you want something more official. Visit the “Domains” tab under your project’s “Settings”.

Adding Production ENV Keys

For more sensitive environment variables like APP_KEY or various API keys, you can visit the “Environment Variables” tab in your project’s “Settings”:

These will now be picked up by your Laravel app in production.

Finishing Up

So there you have it. Free, easy, serverless Laravel deployments.

This makes it incredibly easy to get proof-of-concepts online quickly, or even larger applications.

I personally use this set up for small, non-critical applications.

My most recent project was a GitHub bot for the Livewire repository. Vercel is the perfect case for something small and isolated like that.

One big hole in what I’ve laid out so far is the lack of database support.

Because Vercel is serverless, your database has to be hosted on a separate cloud platform like AWS.

Setting up a MySQL database with AWS and linking to it with Vercel is actually not that complex and I may cover it in a future post if you bug me enough on Twitter 😛.

Thanks for following along, I hope this improves your life ❤️, Caleb


My Newsletter

I send out an email every so often about cool stuff I'm working on or launching. If you dig, go ahead and sign up!