- What: PHP on AWS Lambda (via Bref) adds ~250ms cold start latency, hitting under 0.3% of requests.
- Why it matters: AWS Lambda SnapStart cannot help PHP because it only supports managed Java, Python, and .NET runtimes.
- What to do: Fix package size, memory, and bootstrap first; reach for provisioned concurrency only when p99 truly matters.
- Key stat: A 5M-request PHP API at 1024MB and 180ms average costs about $9.13/month in Lambda fees alone.
AWS Lambda cold starts for PHP average 250ms using the Bref runtime and occur in under 0.3% of invocations on apps with regular traffic. SnapStart cannot fix this because it only supports Java, Python, and .NET managed runtimes, not the custom provided.al2023 runtime PHP depends on. Reduce impact with smaller packages, 1024MB memory, and provisioned concurrency for latency-critical routes.
A Lambda cold start is the latency added when AWS Lambda provisions a new execution environment for a function invocation instead of reusing a warm one, covering package download, runtime initialization, and any bootstrap code before the handler runs. For PHP, which has no native Lambda runtime, cold starts also include starting the Bref custom runtime on top of Amazon Linux 2023, and they cannot be eliminated by AWS Lambda SnapStart because SnapStart is restricted to managed Java, Python, and .NET runtimes.
I moved a mid-traffic Laravel billing API to Lambda last quarter, and the first question every developer on the team asked was the same one I see on every PHP subreddit and Stack Overflow thread: “just turn on SnapStart, right?” It’s not that simple for PHP, and most of the articles ranking for “Lambda cold starts” today either ignore PHP entirely or repeat the general serverless advice that applies to Python and Node without checking whether it holds for a custom runtime. It mostly does, with one hard exception. PHP runs on Lambda exclusively through third-party runtimes like Bref, and that architectural fact rules out AWS’s flagship cold-start fix before you’ve written a line of code. Here’s what the numbers actually look like, why SnapStart is a dead end for PHP, and what to do instead.
How Bad Are AWS Lambda Cold Starts for PHP in 2026?
Cold starts for PHP on Lambda add about 250ms on average and affect fewer than 0.3% of invocations on an application with regular traffic. Bref’s own benchmarks show the FPM runtime adds effectively zero overhead to warm requests: an empty PHP app returns in 1ms at 1024MB, and a minimal Symfony “hello world” responds in 4ms, matching a classic Nginx/PHP-FPM server.
The event-driven function runtime (used for SQS workers and async jobs, not HTTP) carries more startup overhead: 175ms at 128MB down to 13ms at 2048MB, because the PHP executable restarts on every invocation. Setting BREF_LOOP_MAX keeps the process alive across multiple invocations and removes most of that cost. On my billing API, cold starts showed up almost exclusively right after a deploy, when every warm environment gets recycled at once — not during normal traffic.
functions:
worker:
handler: src/Handler.php
runtime: php-84
environment:
BREF_LOOP_MAX: 100
Treat cold starts as a deploy-time spike to monitor, not a permanent tax on every user request.
Why Doesn’t AWS Lambda SnapStart Support PHP?
SnapStart doesn’t support PHP because it only works with AWS-managed runtimes — Java 11+, Python 3.12+, and .NET 8+ — and explicitly excludes OS-only and container-image runtimes. PHP has no managed Lambda runtime at all. It runs through provided.al2023, Amazon’s OS-only base, with Bref supplying the actual PHP binary and FPM process as a layer or container image.
SnapStart works by taking a memory snapshot of an initialized execution environment and resuming from it instead of booting cold. That snapshot mechanism is tied to the JVM, CPython, and .NET CLR internals AWS has specifically engineered for. Bref, Go binaries, Rust binaries, and every other custom runtime sit outside that architecture. Unless AWS ships a first-party PHP runtime, which it has never signaled any intent to do, PHP developers should stop waiting for SnapStart and optimize what’s actually controllable: package size, memory, and bootstrap work.
I’ve seen teams delay a Lambda migration by months hoping AWS would “eventually” extend SnapStart to custom runtimes. Don’t plan around it — plan around Bref’s own cold-start toolkit instead.
How Do You Reduce PHP Cold Starts on AWS Lambda?
You reduce PHP cold starts by shrinking the deployment package, giving the function enough memory, and avoiding blocking work during bootstrap. In order of impact:
- Install dependencies with
composer install --no-dev --classmap-authoritativeto cut package size and autoloader overhead. - Exclude tests, docs, and dev-only assets from the deployment package explicitly in
serverless.yml. - Start at 1024MB memory — Lambda’s CPU scales with memory, and going lower rarely saves money once execution time is factored in.
- Let Bref cache Laravel config and routes on cold start rather than baking absolute local paths into a pre-built cache.
- Move network calls (database pings, third-party API warmup) out of service provider boot logic and into lazy-loaded clients.
- For zip deployments, skip opcache pre-warming — it only pays off with container image deployments on PHP 8.5’s
opcache.file_cache_read_onlyoption.
Matthieu Napoli, Bref’s maintainer, measured a 40% cold start reduction combining container image deployment with pre-compiled opcache on PHP 8.5 — but only after ruling out zip-based opcache caching, which made cold starts worse by inflating package size. Start with the package and memory fixes above before touching opcache; they cost nothing and produce most of the win.
Does Memory Size Affect Lambda Cold Start Cost?
Yes — more memory means more CPU, and PHP’s CPU-bound work finishes faster without necessarily costing more, since Lambda bills GB-seconds. Bref’s benchmarks with PHP’s official bench.php script show execution time dropping from 5.7s at 128MB to 1.4s at 512MB, 0.65s at 1024MB, and 0.33s at 2048MB.
Because Lambda bills memory × duration, a function running 400ms at 512MB costs the same as one running 200ms at 1024MB: both equal 0.20 GB-seconds. Going smaller to “save money” backfires the moment the slower CPU pushes duration up proportionally or further. Bref’s official recommendation, which matched what I saw in production, is to start at 1024MB and only tune down after measuring p50/p95/p99 with real traffic.
512 MB for 400 ms = 0.5 GB * 0.4 s = 0.20 GB-s
1024 MB for 200 ms = 1.0 GB * 0.2 s = 0.20 GB-s
Don’t guess at memory size — benchmark at 1024MB first, then adjust based on measured billed duration, not intuition.
How Much Does a PHP Lambda API Actually Cost?
A PHP API on Lambda at 1024MB and 180ms average duration costs about $9.13/month for 5 million requests after the free tier, scaling to roughly $69.80 at 50 million requests and $213.13 at 100 million requests. Lambda pricing breaks into two components: $0.20 per million requests, and $0.0000166667 per GB-second of compute, with a monthly free tier of 1 million requests and 400,000 GB-seconds.
| Workload | Requests/month | Avg duration | Lambda-only cost |
|---|---|---|---|
| Internal admin tool | 200,000 | 300ms | $0.00 (within free tier) |
| Growing API | 5,000,000 | 180ms | $9.13 |
| Hot JSON API | 50,000,000 | 80ms | $69.80 |
| Busy public endpoint | 100,000,000 | 120ms | $213.13 |
That table excludes API Gateway, CloudFront, CloudWatch Logs, RDS, and NAT Gateway charges — for most PHP apps I’ve deployed, the database costs more than Lambda compute by a wide margin. Don’t celebrate a cheap Lambda line item while an oversized always-on RDS instance and a forgotten NAT Gateway quietly double the actual bill.
Should You Use Provisioned Concurrency for PHP on Lambda?
Use provisioned concurrency only when a specific p99 latency requirement can’t tolerate occasional 250ms cold starts, because it converts part of your bill from pay-per-use to reserved warm capacity you pay for whether or not it’s invoked. It eliminates cold starts for the exact concurrency level you configure; traffic above that level still falls back to on-demand cold starts.
functions:
web:
handler: public/index.php
runtime: php-84-fpm
memorySize: 1024
provisionedConcurrency: 2
For low-traffic internal tools, a scheduled warmer invocation every 5 minutes is usually cheaper than provisioned concurrency and keeps at least one environment hot. For customer-facing checkout or auth endpoints where a 250ms spike on 0.3% of requests genuinely matters, provisioned concurrency is worth the fixed cost. For everything in between, it’s an expense chasing a problem your users mostly can’t perceive.
When Should You Avoid Lambda for PHP Apps?
Avoid Lambda for PHP workloads that need long-running processes, WebSocket connections, or sub-100ms p99 latency on every single request without exception. Bref fits stateless Laravel and Symfony apps well — uploads to S3, sessions in Redis or the database, logs to stderr — but it’s the wrong target for stateful legacy apps tied to local disk, forever-running queue workers, or large file uploads proxied through PHP instead of pre-signed S3 URLs.
On the billing API migration, the parts that moved cleanly to Lambda were the HTTP API and scheduled cron jobs; the parts we kept on ECS Fargate were a long-running webhook consumer that needed to hold open connections longer than Lambda’s timeout comfortably allows. Mixing both on the same AWS account is normal — Lambda isn’t an all-or-nothing decision.
| Option | Performance | Complexity | When to Use |
|---|---|---|---|
| Lambda + Bref (zip) | ~250ms cold start, 1ms warm overhead | Low — Serverless Framework + Bref plugin | Bursty APIs, webhooks, cron, internal tools |
| Lambda + Bref (container) | Faster cold starts with opcache pre-warm on PHP 8.5 | Medium — Docker build pipeline required | High-traffic APIs needing every cold-start ms |
| ECS Fargate | No cold starts, always-on containers | Medium-high — task defs, ALB, scaling policies | Long-running connections, steady heavy traffic |
| EC2 | No cold starts, full control | High — patching, scaling, monitoring all manual | Legacy stateful apps, predictable constant load |
The NexGismo verdict: Deploy PHP to Lambda with Bref’s zip runtime at 1024MB and stop there for the vast majority of apps — the 250ms cold start on 0.3% of requests is not worth the engineering time most teams spend chasing it. Reserve container-image deployments and opcache pre-warming for genuinely high-traffic APIs where every millisecond of p99 is measured and matters. Skip provisioned concurrency unless a specific customer-facing SLA demands it; for internal tools and bursty webhooks, it’s money spent solving a problem users don’t notice. And stop waiting on SnapStart — it is architecturally locked to managed runtimes and there’s no signal AWS intends to open it to Bref or any custom runtime.
- Bref’s PHP-FPM runtime for Lambda adds effectively zero overhead to warm requests, returning in 1ms for an empty app at 1024MB memory.
- Cold starts average 250ms and occur in under 0.3% of invocations on applications with regular traffic.
- AWS Lambda SnapStart supports only Java 11+, Python 3.12+, and .NET 8+ managed runtimes and explicitly excludes OS-only and custom runtimes like PHP’s provided.al2023 via Bref.
- A 512MB Lambda running 400ms costs exactly the same in GB-seconds as a 1024MB Lambda running 200ms — lower memory does not automatically mean lower cost.
- A PHP API handling 5 million requests/month at 1024MB and 180ms average duration costs approximately $9.13/month in Lambda compute and request fees.
- Container-image deployment with pre-compiled opcache on PHP 8.5’s opcache.file_cache_read_only option cut cold starts by 40% in Bref maintainer benchmarks, but zip-based opcache caching makes cold starts worse.
Frequently Asked Questions
What causes AWS Lambda cold starts?
A cold start happens when Lambda has no warm execution environment available and must provision one: download the deployment package, start the runtime, and run initialization code before your handler executes. For PHP via Bref, this adds roughly 250ms on top of normal request time, and it only affects new or scaled-up execution environments, not every request.
Does AWS Lambda support PHP natively?
No. AWS Lambda has no built-in PHP runtime. PHP runs on Lambda through a custom runtime, almost always Bref, packaged as a Lambda layer or Docker image on top of Amazon Linux 2023’s provided.al2023 base. This custom-runtime status is exactly why PHP cannot use SnapStart.
How do I reduce AWS Lambda cold start time for PHP?
Keep the deployment package small with an optimized Composer autoloader, exclude dev files and tests, start at 1024MB memory, avoid network calls during bootstrap, and let Bref cache Laravel or Symfony config on cold start. For latency-critical endpoints, provisioned concurrency removes cold starts entirely for the concurrency level you pay for.
Is AWS Lambda SnapStart available for PHP?
No, and it won’t be under the current architecture. SnapStart only supports AWS-managed runtimes: Java 11+, Python 3.12+, and .NET 8+. PHP runs as a custom OS-only runtime on provided.al2023 through Bref, and AWS explicitly excludes OS-only and container-image runtimes from SnapStart support.
How much does AWS Lambda cost for a PHP API?
At 1024MB memory and 180ms average duration, 5 million monthly requests cost about $9.13 in Lambda compute and request fees after the free tier. At 50 million requests it rises to roughly $69.80, and at 100 million requests to about $213.13. This excludes API Gateway, CloudFront, logs, and your database, which usually cost more than Lambda itself.
The SnapStart question comes up in nearly every PHP-on-Lambda conversation I have, and the honest answer disappoints people looking for a silver bullet: it’s not coming for custom runtimes, so stop budgeting engineering time around it. The real gains sit in boring places — package size, memory tuning, and knowing when a workload doesn’t belong on Lambda at all. Measure your own p50/p95/p99 with the CloudWatch Logs Insight query in Bref’s docs before touching provisioned concurrency, and you’ll likely find cold starts were never the bottleneck your dashboard made them look like.