Skip to content

Serverless PHP on AWS Lambda with Bref โ€‹

For a long time, "serverless" and "PHP" didn't appear in the same sentence. AWS Lambda has never offered a native PHP runtime. Bref changed that, and with Bref 3.0 released at the end of February 2026, it's a good moment to look at where serverless PHP stands, and where I think it does and doesn't make sense.


๐Ÿงฉ What Is Bref? โ€‹

Bref is an open-source project that provides PHP runtimes for Lambda, built on Lambda's custom runtime support. The runtimes ship as Lambda layers and Docker images. On top of them, Bref adds framework integrations and a plugin for serverless.yml.

There are three runtimes, each named per PHP version:

  • FPM (php-84-fpm) runs web apps through PHP-FPM, so your code works like it does on any server.
  • Function (php-84) runs event-driven handlers for SQS, S3, EventBridge and so on.
  • Console (php-84-console) runs CLI commands such as bin/console or artisan.

Bref 3.0 brought some solid changes:

  • The runtimes were rebuilt on Amazon Linux 2023.
  • PHP 8.5 is supported, and PHP 8.2 is now the minimum.
  • The layers are about 24% smaller. PHP 8.4 went from 69MB to 53MB.
  • The three runtimes now share a single layer per PHP version. If you just set runtime: php-84-fpm in serverless.yml, nothing changes for you.

๐Ÿ› ๏ธ Running Symfony and Laravel โ€‹

Both frameworks have first-class bridges. For Symfony:

bash
composer require bref/bref bref/symfony-bridge --update-with-dependencies

Next, make your Kernel extend Bref\SymfonyBridge\BrefKernel instead of the default base kernel. Lambda's filesystem is read-only apart from /tmp, and the bridge takes care of relocating the cache and logs. A minimal serverless.yml looks like this:

yaml
service: app

provider:
    name: aws
    region: eu-west-2
    environment:
        APP_ENV: prod

functions:
    web:
        handler: public/index.php
        runtime: php-84-fpm
        timeout: 28
        events:
            - httpApi: '*'
    console:
        handler: bin/console
        runtime: php-84-console
        timeout: 120

package:
    patterns:
        - '!node_modules/**'
        - '!tests/**'
        - '!var/**'
        - 'var/cache/prod/**'

plugins:
    - ./vendor/bref/bref

For Laravel, install bref/bref and bref/laravel-bridge. Then generate the config with php artisan vendor:publish --tag=serverless-config. Bref 3 ships a much richer serverless.yml template for Laravel, covering the HTTP API, artisan, SQS queues, S3 storage and CloudFront.

For background work, don't run a long-lived worker. On Lambda, SQS invokes a function for each batch of messages. For Symfony Messenger, that's the bref/symfony-messenger package. For Laravel, the bridge runs queued jobs from SQS in the same way.


๐Ÿš€ Deploying: Serverless Framework, osls and Friends โ€‹

This is the part that changed the most. Bref was built around the Serverless Framework. Then Serverless Framework v4 introduced a licence: organisations with more than $2M in annual revenue need a paid subscription, and every user has to log in or use a licence key. v3 stays open source, but it's no longer maintained.

Bref's answer is osls. It's a community fork of Serverless Framework v3, MIT licensed and maintained by the Bref maintainers. With the 3.0 release, Bref recommends that all users migrate to it. It's a drop-in replacement, and the command you run is still serverless:

bash
npm remove serverless
npm install -g osls
serverless deploy

The other options:

  • Bref Cloud is a commercial dashboard and deployment service, with a bref deploy command.
  • AWS CDK works through the brefphp/constructs project.
  • Terraform, SAM, CloudFormation or Pulumi all work too, but the Bref docs are optimised for serverless.yml.

As someone who uses Terraform for most infrastructure, my pragmatic split is this: Terraform owns the shared plumbing (VPCs, databases, DNS), and osls deploys the Lambda functions themselves. Fighting the Bref defaults isn't worth it.


โ„๏ธ Cold Starts โ€‹

Cold starts are the first objection people raise, and they're usually overestimated. Bref says its runtimes add about 250ms on average. The rest depends on your application, and on an app with regular traffic only a tiny fraction of requests hit one. A few things help:

  • Warm the Symfony cache at deploy time. Otherwise every new instance builds it on the fly.
  • Keep the package small. Exclude tests, assets and node_modules.
  • Don't skimp on memory. Lambda allocates CPU in proportion to memory. Bref recommends starting at 1024MB, which is also the serverless.yml default.
  • Warm low-traffic apps. A scheduled event every few minutes keeps an instance alive. Provisioned concurrency removes cold starts entirely, at a cost.

โš–๏ธ Good Fit or Bad Fit? โ€‹

Good fit:

  • APIs and websites with spiky or unpredictable traffic
  • Queue consumers and scheduled jobs
  • Internal tools that sit idle most of the day
  • Teams who'd rather not patch servers

You pay per request, and scaling is someone else's problem.

Bad fit:

  • Strict latency budgets. Bref's own guidance: if you can't tolerate any response over roughly 300ms, Lambda isn't for you.
  • Long-running work. Lambda caps an invocation at 15 minutes, and API Gateway caps HTTP requests at around 30 seconds.
  • Long-lived processes. A PHP WebSocket server, or anything that relies on in-process state between requests, won't work.
  • Heavy codebases. Zip deployments are limited to 250MB unzipped, including layers. Container images get you up to 10GB, if you need it.
  • Steady, high traffic. At that point, always-on containers may well be cheaper. Do the maths for your own workload.

๐ŸŽฏ Conclusion โ€‹

Bref has made serverless PHP feel ordinary, and I mean that as a compliment. Symfony and Laravel run on Lambda with only a few changes. Bref 3.0 makes the runtimes leaner, and osls removes the licensing worry around the Serverless Framework. It isn't the answer for every workload. But for spiky APIs, workers and cron jobs, it's hard to beat not having servers at all.