Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Vapor Core Laravel Package

laravel/vapor-core

The core service providers and runtime client that power Laravel applications on AWS Lambda. Part of Laravel Vapor, the auto-scaling serverless deployment platform, handling integration with SQS queues, databases, Redis clusters, networks, and CloudFront CDN.

View on GitHub
Deep Wiki
Context7

Getting Started

laravel/vapor-core is not a typical "install and call" package — it is the runtime layer that makes a standard Laravel application bootable inside AWS Lambda. You rarely interact with it through a public API; you interact with it through the constraints it imposes on your app.

Minimal setup:

composer require laravel/vapor-core

The VaporServiceProvider is auto-discovered. There is nothing to publish and no config/vapor.php to tune — configuration lives in vapor.yml (CLI side) and in your application's normal Laravel config. Notably, v2.43.4 made the provider skip registration when the app is detected as running on Laravel Cloud, so the same codebase can deploy to both platforms without a conditional.

Where to look first, in order:

  1. VaporServiceProvider — see what is bound and under what conditions.
  2. Kernel/HttpKernel, Kernel/ConsoleKernel, Kernel/JobKernel — the three entry points Lambda will invoke.
  3. Runtime/Client — the request/response translation between API Gateway payloads and Symfony's Request/Response.

Then verify the environment switch works, because you will use it constantly:

use Laravel\Vapor\Vapor;

if (Vapor::isActive()) {
    // configure CloudWatch-friendly logging, SQS queue driver, etc.
}

First real use case: deploy a plain Laravel app, hit a route, then check that the app correctly identifies its environment and that logs land in CloudWatch. If that works, the rest of your work is adapting stateful assumptions (filesystem, sessions, long-lived singletons) to a reused container.

Implementation Patterns

Environment-gated service providers. The single most useful pattern is isolating Vapor-specific configuration behind Vapor::isActive() (added in v2.33.2). Logging is the canonical case — v2.31.0 added a conditional log wrapper so the same code writes to stderr on Lambda and to files under FPM:

public function register(): void
{
    if (Vapor::isActive()) {
        config(['logging.default' => 'stderr']);
        config(['queue.default' => 'sqs']);
    }
}

Use VAPOR_ENV (v2.37.1) rather than APP_ENV when you need the non-standard Vapor environment name — this matters for anything keyed on environment, including Sentry, Telescope gating, and feature flags.

Structured logging with Lambda context. v2.42.0 exposes the AWS Lambda execution context for logging. Attach it to your log processor so CloudWatch entries carry function name, version, and request ID — it turns "which invocation broke?" into a filterable query rather than a timestamp hunt:

Log::withContext([
    'request_id' => $_SERVER['AWS_LAMBDA_LOG_STREAM_NAME'] ?? null,
    'function'   => $_SERVER['AWS_LAMBDA_FUNCTION_NAME'] ?? null,
]);

HTTP edge cases you will actually hit.

  • Multi-value cookies (v2.44.0): if you set more than one cookie in a response, verify at the HTTP layer, not in a unit test — the API Gateway payload format is where this historically broke.
  • Multipart with nested arrays (v2.37.9): array-style file inputs (attachments[]) and nested form fields parse correctly now, but only for payloads that API Gateway passes through. Validate binary uploads early.
  • Raw query string (v2.46.0) is surfaced as a custom server variable specifically for signature verification. Stripe, GitHub, and Slack webhooks sign the raw query string; use that variable rather than $request->getQueryString() when recomputing HMACs.
  • Streaming responses work under Octane (v2.32.2) — for CSV export or SSE, prefer response()->stream() over building a large string, given Lambda's payload ceiling.
  • Request timestamp is available in server variables (v2.39.0) — useful for latency measurement that starts at the edge, not at your first middleware.

Queues and jobs. The JobKernel handles SQS and custom Lambda events (v2.41.0), and Laravel 13 SQS overflow is supported (v2.45.0). Practical implications:

  • Jobs must be idempotent. Lambda retries on failure and SQS redelivers.
  • Keep batch sizes small relative to Lambda timeout; a batch is processed in one invocation.
  • If you dispatch a job from within a job, confirm the queue connection resolves to SQS and not sync.
  • v2.37.2 resets scoped instances before each job. If you have stateful services, register them as scoped rather than singleton and they will be discarded between invocations in the same container.

Console and scheduling. Artisan commands run via a dynamic CLI handler factory (v2.43.0). Sub-minute schedules are normalized by a scheduler proxy command (v2.34.0) — you can write everyTenSeconds() in routes/console.php and it will be honored, but remember the granularity is bounded by how often the schedule Lambda fires. For anything under a minute, prefer an SQS-driven loop or EventBridge rule.

Database and cache resilience. Two changes reflect real production pain:

  • RDS CA certificates are bundled (v2.33.0/2.33.1), so DB_*_SSL_CA can point at the packaged certificate rather than a path you must bake into the image.
  • v2.43.3 catches PDOException on "MySQL server has gone away" while resetting wait_timeout. Long-lived containers hold connections across idle periods; you should still set DB_POOL-style reconnect behavior and catch QueryException with isLostConnection() in critical paths.
  • Serverless ElastiCache is supported (v2.35.0); treat cold-start cache connections as recoverable, not fatal.

Storage parity. v2.38.0 fixed S3-compatible storage support, which is what lets you run the same filesystem config against MinIO under Herd or Docker locally. Use one disk name (s3) and swap the endpoint, rather than branching on environment.

Gotchas and Tips

Container reuse is the #1 source of bugs. Lambda keeps the PHP process alive across invocations. Any static cache, memoized array, or singleton holding request data will leak into the next request. Audit for classes that assign $this->request, accumulate counters, or cache authorization decisions. Mark them scoped, or reset in a terminating callback.

Never call exit or die. A hard exit kills the runtime before the response is written back to API Gateway, producing a 502 with a log that looks like a successful request. This includes dd(), var_dump()-then-exit debugging, and any library that short-circuits.

The filesystem is read-only except /tmp. /tmp is per-container, size-limited, and evaporates on cold start. Anything that must survive belongs on S3. storage_path() writes will fail — move those to the s3 disk explicitly.

Config cache changes the env() story. env() outside config files returns null after config:cache, and Vapor caches config at build time. Read runtime values through config(), and set them in vapor.yml under environment:. This is the most common "works locally, null in prod" failure.

Timeout mismatches silently truncate work. Lambda caps at 15 minutes. Set your vapor.yml timeout slightly above the queue job's $timeout (and retry_after above both) or jobs get killed mid-flight and redelivered without ever being marked failed.

Payload limits bite before PHP limits. API Gateway and Lambda have request/response size ceilings well below what you may be used to on FPM. Large Set-Cookie payloads, base64-inflated binary responses, and big JSON responses are all candidates for truncation. If a response works locally and 502s remotely, check size first.

Debugging follows CloudWatch, not storage/logs. Use vapor tail or the CloudWatch console. Because logging is a conditional wrapper on Lambda (v2.31.0/v2.31.1), a mis-set logging.default will silently swallow output — confirm the channel before you conclude your code isn't running. The health check improvements in v2.36.0 also give you a cheap liveness probe to distinguish "app boots" from "app handles requests."

Extension points, ranked by risk. Prefer, in order: environment-gated providers → custom Log processors → a custom queue job handler → replacing the HttpKernel binding. The last one is the highest-risk because the handler contract is what API Gateway speaks; a mistake there manifests as opaque 502s rather than exceptions.

Guard against double-encoding. If you construct Lambda responses manually, remember the X-Vapor-Base64-Encode header semantics: binary bodies must be base64-encoded once and flagged, not encoded inside an already-encoded payload.

Test at the boundary, not the unit. Request tests with server variables mimicking API Gateway shape catch almost every regression class in this package:

$this->withServerVariables([
    'HTTP_X_FORWARDED_FOR' => '203.0.113.1',
    'QUERY_STRING' => $rawQueryString,
])->get('/webhook');

Keep register() cheap. Every provider boot is paid on cold start. Deferred providers, lazy service resolution, and avoiding package discovery for dev-only tooling all directly reduce p99 latency on low-traffic functions — which, on Lambda, is most of them.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo
bernskioldmedia/laravel-harvest
bernskiold/laravel-data-scrubber
bernskiold/laravel-currency-converter
bernskiold/laravel-campaign-monitor
bernskioldmedia/laravel-autotranslate
siberfx/telegram-bot
roy-sandip/laravel-view-extended
gregsphotography/site-builder-core
roy-sandip/laravel-view
anodyne/blade-fluentui-icons
webx-ui/module-catalog-collections