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

Sidecar Laravel Package

hammerstone/sidecar

Sidecar lets your Laravel app package, deploy, and execute AWS Lambda functions in Node, Python, Java, .NET, Ruby, or custom runtimes. Define a PHP class and files, then invoke serverless functions directly from PHP.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install: composer require hammerstone/sidecar
  2. Publish config + set up AWS IAM: php artisan sidecar:install then php artisan sidecar:configure. The configure command creates the IAM user/role Sidecar needs (Lambda CRUD, S3, ECR, CloudWatch Logs) and writes SIDECAR_* keys into .env. Run it while authenticated as an AWS admin once; afterwards use the generated keys.
  3. Create your first function in app/Sidecar/:
    class OgImage extends \Hammerstone\Sidecar\LambdaFunction
    {
        public function handler() { return 'image.handler'; }
        public function package() { return ['resources/lambda']; }
        public function runtime()  { return \Hammerstone\Sidecar\Runtime::NODEJS_20; }
    }
    
  4. Write the handler (resources/lambda/image.js) exporting exports.handler = async (event) => {...}. The event is exactly the array/object you pass to execute().
  5. Deploy: php artisan sidecar:deploy --activate — this creates the function, publishes a version, and points the live alias at it.
  6. Call it: OgImage::execute(['text' => 'Hello']) returns a SettledResult-style wrapper — call ->get() for the response body or ->hasError() to inspect failures.

First real use case: something you cannot do in PHP but need inline — OG image rendering, headless-Chrome screenshots, PDF generation, Python data munging, image resizing. Reach for Sidecar when a function's latency budget is ~hundreds of ms and you don't want to stand up a second service.

The full docs live at hammerstone.dev/sidecar/docs; the config file config/sidecar.php is the second place to look — most surprising behavior lives there.

Implementation Patterns

Function class as the unit of everything. Every concern (handler, runtime, memory, timeout, env vars, packaging, layers) is overridable on the LambdaFunction subclass. Treat each subclass as a deployable artifact and keep one repo file per function.

Packaging. Return directory names relative to base_path() from package() (['src/lambda', 'vendor/function']), or use the fluent builder for control:

public function package()
{
    return Package::make()
        ->include('resources/lambda')
        ->includeExactly('node_modules', followLinks: false)
        ->exclude('**/*.test.js');
}

Include node_modules manually — Sidecar does not run npm install for you. A common pattern is a shell script or CI step that runs npm ci --omit=dev in the function folder before sidecar:deploy.

Sync vs. async invocation.

  • MyFn::execute($payload) — synchronous, waits for the response. Use for request-response.
  • MyFn::executeAsync($payload) — returns 202 immediately. Use for fire-and-forget.
  • MyFn::event($payload) — for event-source-mapped invocation (S3, SQS, etc.).

Pending results. execute() returns a pending result you can chain:

$result = MyFn::execute(['x' => 1]);
$result->then(fn ($response) => /* ... */);
$result->wait(); // returns SettledResult
$result->get();  // throws on Lambda error, returns payload
$result->settle(); // never throws; inspect with ->hasError(), ->errorAsString()

Batch a set of invocations, kick them off, then loop ->wait() — each call is a separate HTTP request to Lambda, so a fan-out of 20 is fine but 200 is not.

Environment separation. Set sidecar.env in config/sidecar.php (or SIDECAR_ENV) so a shared local APP_ENV across the team doesn't make everyone overwrite the same Lambda. Typical setup: sidecar.env = 'local-'.Str::slug(gethostname()) locally, production in prod. Function names, log groups, and aliases all scoped by this.

Env vars and checksums. variables() merges with config('sidecar.envVars'). Sidecar computes a checksum of variables and only publishes a new version if they actually changed — so redeploying for a code-only change won't churn versions. Reference Laravel config via env() in the function class (config is serialized at deploy time, not runtime — do not expect runtime env() lookups).

Deploy only what changed. php artisan sidecar:deploy MyFnName --activate deploys a single function. Wire this into per-function CI jobs. --activate moves the alias; omit it to deploy a version without promoting it, useful for smoke-testing before cutover.

Warming. php artisan sidecar:warm MyFnName 3 keeps 3 instances hot; sidecar:deploy --pre-warm warms immediately after deploy. Warming is opt-in (0 by default since v0.2.0) because it costs money. Use it only on user-facing latency-sensitive functions.

Event-invocation integration. Use MyFn::event($payload) from a queued job or observer to kick off async work without blocking the HTTP request. Since Sidecar doesn't give you an HTTP endpoint, this is your "call into Lambda from a side-effect" pattern.

Gotchas and Tips

  • Default runtime changed in v0.6.0 (Node 14 → Node 20). If your function class doesn't override runtime(), upgrades silently move you. Always pin runtime() explicitly, especially across major Sidecar updates.
  • Function naming changed in v0.4.0 (breaking). If you're upgrading from pre-0.4, expect the same class to deploy to a different physical Lambda; old functions are orphaned and still cost money — clean up CloudWatch/versions manually.
  • node_modules is not auto-included. A handler that works npm start-style locally will 404 on Lambda if you only ship resources/lambda. Include node_modules in package(), and prune dev deps — 50 MB zip / 250 MB unzipped is the direct-upload ceiling; beyond that Sidecar routes through S3, which needs the bucket permission from sidecar:configure.
  • execute() is a blocking HTTP call. If the PHP request times out before Lambda does, you get a GuzzleException while the Lambda keeps running. Set timeout() shorter than your PHP max execution time, or use executeAsync().
  • settle() for fire-and-forget error handling. get() throws HttpException on the transport layer and LambdaError for the function's own error; errorAsString on the settled result gives you the CloudWatch-style trace. Log that — raw Lambda errors are opaque otherwise.
  • 409 conflicts are handled in middleware since v0.3.6, but the classic symptom (deploy fails right after an env-var update) came from not waiting for the function to be LastUpdateStatus: Successful. If you script around deploy, invoke sidecar:deploy rather than calling the AWS SDK directly — the wait logic is inside the command.
  • Arrayable payloads are auto-cast to arrays. Passing an Eloquent model just works; passing a raw Collection does not — call ->toArray() first.
  • Path separators normalize to / since v0.3.10. Don't hand-write DIRECTORY_SEPARATOR in package() paths; it broke Windows users pre-0.3.10 and is now fixed.
  • Container images (v0.3.2+) change the workflow significantly. You supply an ECR image, Sidecar builds/pushes it, but you no longer get a free package() — the image has to contain the handler and all deps. Stick to zip packaging unless you genuinely need >250 MB or native binaries.
  • Architecture is per-function. architecture(LambdaFunction::ARM64) is cheaper and usually faster for Node/Python, but check for native modules (sharp, canvas, image magick) — they need ARM builds. Default is x86_64.
  • No API Gateway, no HTTP. Sidecar is deliberately scoped to invoke-from-PHP. If you need a public endpoint, use Vapor or a separate serverless project. Don't try to hack executeAsync() into an HTTPS trigger — you'll lose auth, retries, and request validation.
  • Sidecar does not manage S3/ECR lifecycle itself — old versions accumulate. sidecar:deploy sweeps old aliases but not versions/ECR images. Set a CloudWatch lifecycle and an ECR lifecycle policy, or you'll pay for stale artifacts.
  • Debugging. php artisan sidecar:list shows deployed functions in your sidecar.env. sidecar:deploy prints the CloudFormation-ish JSON returned by AWS — read it when a deploy "succeeds" but the alias is wrong. For runtime errors, tail the function's CloudWatch log group (/aws/lambda/<prefix>-<fn>-<env>); settle()->errorAsString only shows the crash summary, not console.log output.
  • sidecar:configure must run with admin credentials. It creates an IAM user, attaches a policy, sets the access key. Re-running it rotates the access key and rewrites .env — safe, but don't run it in a shared environment without coordinating.
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.
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc
animalyoung/laravel-influxdb
onix-solutions/sms-telera
lonely-lights/prosetta
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log