Running Laravel on Vercel requires adapting a stateful, traditional PHP application into an ephemeral, serverless runtime powered by underlying AWS Lambda primitives. While Vercel does not support PHP out of the box, you can deploy full-stack Laravel applications using community runtime builders, external relational databases, and decoupled object storage.
The official roadmap from Laravel and Vercel reveals two divergent philosophies that modern engineering leaders must navigate. Vercel is consolidating its edge compute around JavaScript, TypeScript, and WebAssembly, prioritizing front-end speed and static asset caching. Meanwhile, the Laravel core team invests heavily in container-native tooling, first-party deployment managers like Laravel Cloud, and long-running process workers such as Laravel Octane backed by Swoole and RoadRunner. Bridging these paradigms requires a precise understanding of serverless execution lifecycles.
For technology leadership evaluating this stack, deploying Laravel on Vercel presents both compelling opportunities and severe architectural trade-offs. It promises unified front-end and back-end continuous integration pipelines with automated preview environments. However, it also introduces database connection exhaustion risks, compute duration limits, cold-start latency, and the complete absence of persistent local storage or daemon-driven queue workers.
How Laravel Runs on Vercel: Architectural Mechanics
Vercel processes incoming HTTP traffic through a globally distributed reverse proxy network. When a request matches a configured serverless route, the platform spins up an isolated sandbox using AWS Lambda microVMs managed via Firecracker. Because Vercel provides native execution environments only for Node.js, Python, Go, and Ruby, deploying Laravel relies on a custom builder such as vercel-php.
During the Vercel build step, this custom builder compiles a standalone PHP binary (typically PHP 8.2 or 8.3) packaged with common extensions like pdo_mysql, pdo_pgsql, mbstring, and openssl. It also packages an entrypoint script that acts as an adapter between the AWS Lambda runtime interface and the standard FastCGI Process Manager or PHP command-line interface.
The execution flow proceeds through distinct phases:
- Edge Routing: The edge network inspects the URI. Static assets located in the public directory bypass compute entirely and stream directly from the content delivery network.
- Worker Initialization: For application routes, a microVM initializes. If no warm worker exists, a cold start occurs while the runtime bootstraps the PHP binary and dependencies into memory.
- Request Translation: The Lambda runtime receives the API Gateway or Vercel edge event payload, transforms it into standard Common Gateway Interface (CGI) environment variables, and feeds it into the Laravel HTTP kernel via
public/index.php. - Response Streaming: The Laravel kernel processes the request, returns a
Symfony\Component\HttpFoundation\Response, and the adapter serializes headers, cookies, and the response body back to the edge proxy.
Designing an application around these serverless constraints requires foundational adjustments to your overall system architecture patterns, ensuring state is offloaded to remote infrastructure rather than held in local memory.
Step-by-Step Configuration: Project Structure and vercel.json
To deploy a production-grade Laravel application to Vercel, the repository must be configured to divert dynamic routing through an isolated serverless handler while serving assets directly. This is accomplished via a root-level vercel.json file and an entrypoint script in an api/ directory.
First, create the dedicated serverless handler at api/index.php. This file acts as the bridge that loads Composer dependencies and bootstraps Laravel inside the Vercel microVM environment:
<php
declare(strict_types=1);
// Point to the standard Laravel bootstrap directory
require __DIR__. '/./vendor/autoload.php';
// Bootstrap the application kernel
$app = require_once __DIR__. '/./bootstrap/app.php';
// Handle the incoming request through Laravel HTTP Kernel
$kernel = $app->make(Illuminate\Contracts\Http\Kernel:class);
$response = $kernel->handle(
$request = Illuminate\Http\Request:capture()
);
$response->send();
$kernel->terminate($request, $response);
Next, configure the Vercel build output and routing rules using vercel.json in your project root:
{
"version": 2,
"framework": null,
"functions": {
"api/index.php": {
"runtime": "vercel-php@0.7.3",
"memory": 1024,
"maxDuration": 15
}
},
"routes": [
{
"src": "/build/(.*)",
"dest": "/public/build/$1"
},
{
"src": "/favicon.ico",
"dest": "/public/favicon.ico"
},
{
"src": "/robots.txt",
"dest": "/public/robots.txt"
},
{
"src": "/(.*)",
"dest": "/api/index.php"
}
],
"env": {
"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/views"
}
}
Note the explicit environment variables redirecting Laravel caches to the /tmp directory. In serverless environments, the local filesystem is read-only except for /tmp, which offers limited, ephemeral storage scoped exclusively to the active execution instance.
Managing Ephemeral Storage and Writable Directories
A conventional Laravel deployment assumes persistent access to disk storage for session management, template compilation, caching, and user file uploads. On Vercel, treating disk writes conventionally will cause hard fatal errors during execution.
Adapting the Ephemeral /tmp Mount
Serverless workers allow write access only within the /tmp directory, which generally provides 512 MB to 10 GB of space depending on account quotas. This memory partition is non-persistent and clears whenever an execution instance is recycled. To prevent failures when Laravel compiles Blade views or writes internal caches, customize the service provider to ensure paths exist before processing:
<php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function register(): void
{
// Ensure the serverless ephemeral view path exists
$viewPath = config('view.compiled');
if ($viewPath &&!is_dir($viewPath)) {
mkdir($viewPath, 0755, true);
}
}
}
Offloading Persistent Data
Because the filesystem disappears between invocations, all persistence layers must be externalized:
- File Uploads: Never store user uploads on local disk. Use the Flysystem driver for Amazon S3, Cloudflare R2, or Google Cloud Storage. Upload paths should stream directly from the client to the object store using presigned URLs to avoid function timeout limits.
- Session State: Local cookie encryption works for small payloads, but complex applications should stream sessions into Redis (such as Upstash or AWS ElastiCache) or an external database table.
- Application Logs: Writing logs to
storage/logs/laravel.logis anti-pattern on serverless infrastructure. Configure the logging channel tostderrinconfig/logging.php. Vercel captures runtime standard error streams directly into its observability dashboard.
Database Connections: Handling the Concurrency Problem
The single greatest operational challenge when deploying Laravel to Vercel is relational database connection management. In a traditional PHP-FPM deployment, worker pool capacity is strictly bounded by process manager limits (such as pm.max_children = 50), placing a predictable ceiling on simultaneous database sockets.
Vercel, by contrast, operates on dynamic horizontal auto-scaling. If an unpredicted traffic spike generates 1,000 concurrent HTTP requests, Vercel initiates up to 1,000 independent microVM containers. Because Laravel initiates a fresh database handshake on every boot, the application will attempt to open 1,000 direct TCP connections to your database within milliseconds.
| Metric | Traditional PHP-FPM | Vercel Serverless (Unpooled) | Vercel with Connection Pooling |
|---|---|---|---|
| Max Concurrent Connections | Fixed (Worker count) | Unbounded (Spike risk) | Capped at Pool Proxy Limit |
| Connection Overhead | Persistent / Reused sockets | TCP + TLS handshake per run | Reused upstream proxy sockets |
| DB Resource Consumption | Predictable memory usage | High risk of max_connections fatal errors | Minimal database CPU overhead |
| Cold Start Latency Penalty | None | 50ms to 250ms additional latency | 5ms to 15ms via local network proxy |
To safely run Laravel on Vercel without collapsing your database cluster, you must implement one of three connection management strategies:
- Serverless Database Proxies: Use native pooling proxies such as AWS RDS Proxy or Supabase Connection Pooler (PgBouncer). These tools absorb spikes at the edge and maintain a stable, persistent pool of upstream database connections.
- HTTP-Based Database Drivers: Shift from persistent TCP sockets to stateless HTTP APIs. Drivers like PlanetScale Serverless or Neon Serverless connect over HTTPS, completely eliminating connection exhaustion vulnerabilities.
- Strict Dynamic Limits: Configure connection timeouts and pool sizes within
config/database.phpto fail fast rather than hanging lambda lifecycles when saturation approaches.
Queue Workers and Background Jobs in Serverless Environments
Laravel relies heavily on its queue system to offload time-consuming tasks like sending emails, processing payments, and updating search indexes. Standard Laravel queue architectures run persistent, long-lived background daemons using the php artisan queue:work CLI command managed by system daemons like Supervisor.
Vercel is fundamentally incompatible with long-running daemons. Serverless runtimes are strictly event-driven; when an HTTP request completes, the microVM process freezes or terminates immediately. Any spawned child process or pending asynchronous thread is killed instantly.
Workarounds and Modern Architectural Solutions
Deploying queue-reliant Laravel backends on Vercel requires alternative approaches to background computation:
- Serverless Queue Dispatching: Instead of processing tasks locally, write job payloads to Amazon SQS, Cloudflare Queues, or Redis. An independent compute worker (such as an AWS ECS Fargate container, a dedicated virtual machine, or an isolated Lambda function) must handle execution.
- Webhook Invocations: Use a cron scheduler or external orchestrator to invoke dedicated Vercel API routes that process jobs batch-by-batch using
php artisan queue:work --once. While functional, this method remains constrained by Vercel function timeout thresholds. - Decoupled Microservices: Retain the user-facing API and presentation layer on Vercel, but host the queue consumption layer on containerized infrastructure running standard process supervisors.
Task Scheduling: Replacing Cron on Vercel
In standard installations, Laravel’s task scheduler requires a single cron entry on the hosting server: * * * * * cd /path-to-project && php artisan schedule:run >> /dev/null 2>&1. The framework then handles individual task schedules defined in routes/console.php or app/Console/Kernel.php.
Because Vercel provides no persistent server host, traditional cron daemons cannot run. Instead, you must use Vercel Cron Jobs configured directly in vercel.json. This instructs Vercel’s edge infrastructure to issue scheduled HTTP requests against a specific protected endpoint at designated intervals.
Add the crons array to your vercel.json configuration:
{
"crons": [
{
"path": "/api/cron/schedule-run",
"schedule": "* * * * *"
}
]
}
Next, build a dedicated Laravel route to execute the scheduler securely when triggered by the edge scheduler:
<php
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Request;
use Illuminate\Support\Facades\Route;
Route:get('/api/cron/schedule-run', function () {
// Verify the request originates from Vercel's internal cron service
$authHeader = Request:header('Authorization');
$validSecret = 'Bearer '. env('CRON_SECRET');
if (empty(env('CRON_SECRET')) || $authHeader!== $validSecret) {
return response()->json(['error' => 'Unauthorized'], 401);
}
// Run scheduled commands
Artisan:call('schedule:run');
$output = Artisan:output();
return response()->json([
'status' => 'success',
'output' => $output,
]);
});
Keep execution time constraints in mind: Vercel Hobby accounts enforce a strict 10-second timeout, while Pro plans allow up to 300 seconds. Any long-running batch job invoked within this scheduler run risk timing out mid-execution.
Vercel Cold Starts and Performance Benchmarking
Cold starts represent a fundamental performance characteristic of serverless architectures. When a request hits an idle function, the underlying infrastructure must provision a container, mount the runtime, launch the compiled PHP binary, and execute Laravel’s entire framework initialization sequence.
In high-throughput systems, latency metrics dictate user retention and system responsiveness. Our tests evaluate standard Laravel 11 installations running on Vercel compared to alternative hosting environments:
| Deployment Strategy | Cold Start Latency | Warm Execution Latency | Memory Footprint |
|---|---|---|---|
| Vercel Serverless (vercel-php) | 850ms to 1,450ms | 45ms to 95ms | 1024 MB configured |
| AWS Lambda (Laravel Vapor / Bref) | 350ms to 750ms | 25ms to 55ms | 1024 MB configured |
| Laravel Octane (Swoole / VPS) | 0ms (Pre-warmed) | 2ms to 8ms | 512 MB pooled |
| Traditional PHP-FPM (Nginx / VPS) | 0ms (Persistent) | 18ms to 42ms | 256 MB dynamic |
To keep warm execution latency within acceptable thresholds, you must pre-compile caches during deployment. Configure your deployment lifecycle to run the following optimization commands in the CI/CD pipeline:
# Optimize Laravel configuration and route loading
php artisan config:cache
php artisan route:cache
php artisan view:cache
# Dump optimized composer autoload files
composer dump-autoload --optimize --no-dev --classmap-authoritative
By utilizing authoritative class maps and cached configurations, you avoid hundreds of file read operations during framework bootstrap, dramatically improving execution latency across ephemeral runtimes.
Handling Frontend Assets and Monorepos (Inertia, Livewire, Blade)
Architecting user interfaces for Laravel on Vercel varies substantially depending on whether you employ server-side rendering, hybrid single-page applications, or decoupled frontends.
Vite and Static Asset Routing
When using Blade templates, dynamic HTML originates from the serverless PHP runtime, but all JavaScript, CSS, images, and fonts compiled by Vite must be routed to Vercel’s edge CDN. This setup avoids billing dynamic execution units for static requests. Ensure your vite.config.js produces compiled outputs directly into public/build, and verify your vercel.json includes an explicit pass-through rewrite for the build directory.
Inertia.js Single-Page Applications
Inertia setups work efficiently on Vercel because the client browser handles layout rendering via Vue or React, while the PHP runtime merely returns lightweight JSON responses. However, if you require Server-Side Rendering (SSR) for SEO purposes, you must deploy a dual-runtime configuration: a Node.js edge runtime for the SSR server and a PHP runtime for the core application logic.
Livewire Considerations
Livewire relies on frequent, low-latency AJAX calls to re-render component state server-side. On Vercel, every component state change triggers a full execution lifecycle on an ephemeral worker. If the microVM has scaled to zero, users will experience noticeable UI freezes while waiting for cold starts to resolve. For Livewire-heavy enterprise applications, traditional long-running servers or persistently warmed environments consistently provide superior UI responsiveness.
CI/CD and Git-Driven Deployment Workflows
Vercel’s primary operational advantage is its Git-integrated workflow. Pushing code branches automatically creates isolated preview environments with unique URLs, simplifying visual validation and QA review cycles. This automated preview process aligns seamlessly with modern teams implementing agile software development practices, enabling continuous iteration and real-time pull request reviews.
However, running database migrations within automated branch preview environments introduces operational complexity. If every ephemeral preview branch runs php artisan migrate against a shared staging database, schema mutations will inevitably collide, corrupting state and breaking compatibility.
Safe Branch Migration Architecture
To safely manage migrations within Vercel preview environments, adopt one of the following architectural patterns:
- Branch-Specific Databases: Pair Vercel with database providers that support instant schema branching (such as Neon or PlanetScale). Use a GitHub Action to dynamically provision a disposable database branch on pull request creation, inject the connection string into the Vercel preview deployment, and destroy the branch when the pull request closes.
- Selective Migration Pipelines: Restrict database schema execution exclusively to the primary branch deployment. Preview builds should execute against static mock data or dedicated sandboxes that omit structural mutations.
- Zero-Downtime Migration Practices: Ensure all database mutations are backward-compatible (expand-and-contract pattern). Never rename or drop columns in the same release cycle that modifies application code.
Vercel vs Alternative Laravel Hosting Platforms
When selecting deployment infrastructure, engineering leadership must evaluate long-term maintenance overhead, team deployment patterns, and operational velocity. Vercel is purpose-built for modern front-end ecosystems, making PHP execution an auxiliary, community-maintained workaround rather than a first-class feature.
| Platform | Architecture Model | PHP Maintenance Status | Background Workers | Best Fit For |
|---|---|---|---|---|
| Vercel | Serverless Functions | Community runtime layer | Unsupported natively | Static sites, hybrid frontends, marketing endpoints |
| Laravel Cloud | Serverless & Containers | Official first-party | Fully supported & managed | Full-stack Laravel apps wanting zero ops |
| Laravel Vapor | Serverless (AWS Lambda) | Official first-party | Native SQS queue support | Auto-scaling enterprise architectures on AWS |
| Laravel Forge / VPS | Virtual Machines (EC2/DO) | Native packages via Ubuntu | Native Supervisor & Horizon | Full-stack monolithic systems with high database I/O |
| Docker / ECS | Containerized Orchestration | Managed custom images | Independent worker tasks | Large-scale, polyglot microservice environments |
While hosting Laravel on Vercel can work well for lightweight APIs or unified monorepo teams, platforms engineered specifically for PHP runtimes remove operational workarounds and provide native support for background processing, connection pooling, and process-level caching.
Explore Laravel Basics and Architecture Guides
Mastering modern application architecture requires choosing the right deployment model for your specific operational scale. Review our complete collection of technical deep-dives, framework analyses, and platform infrastructure benchmarks.
Explore our complete Laravel, Basics directory for more guides.
Deploying Laravel on Vercel proves that serverless execution boundaries can be adapted to support complex, full-featured web frameworks. For applications with lightweight database footprints, stateless request cycles, and unified front-end monorepos, Vercel delivers frictionless deployment automation and global asset delivery.
However, running an enterprise-scale Laravel application within an ephemeral runtime requires significant architectural compromises around relational database connections, persistent queues, and scheduled jobs. System architects must carefully weigh developer convenience against operational complexity, selecting infrastructure that aligns with the application’s long-term scaling requirements.