Documentation
Upgrading
From 2.x to 3.0

Upgrading to Bref 3.0

Read the Bref 3.0 release announcement to learn about all the new features and improvements.

Updating dependencies

PHP 8.2 required

Bref 3.0 now requires PHP 8.2 or greater.

Composer Dependencies

Update all Bref packages in your composer.json file from ^2 to ^3, for example:

composer.json
"require": {
    "bref/bref": "^3",
    "bref/laravel-bridge": "^3",         // if you use Laravel
    "bref/symfony-bridge": "^3",         // if you use Symfony
    "bref/extra-php-extensions": "^3"    // if you use extra extensions
}
💡

Only update the versions for the packages you actually have in your project.

💡

If you use bref/extra-php-extensions (opens in a new tab), note that it jumps from v1 to v3 (there is no v2). The v1 version was used with Bref v2, and v3 is aligned with Bref v3.

Then run:

composer update --with-all-dependencies

PHP extension changes

The following improvements in Bref 3.0 let you clean up old configurations.

PostgreSQL extension is enabled by default

The PostgreSQL PDO extension (pdo_pgsql) is now enabled by default in Bref layers.

If you had enabled it manually via a php.ini file, you can remove that line:

php/conf.d/php.ini
-extension=pdo_pgsql

Redis extension is now built-in

The Redis PHP extension is now included in Bref layers by default.

If you were using the Redis extension from bref/extra-php-extensions (opens in a new tab), remove the layer from your serverless.yml:

serverless.yml
functions:
    api:
        # ...
        layers:
-            - ${bref-extra:redis-php-84}

And enable the extension via a php.ini file in your project (php/conf.d/php.ini):

php/conf.d/php.ini
extension=redis

If Redis was the only bref/extra-php-extensions extension you were using, you can uninstall the package:

composer remove bref/extra-php-extensions

Container image changes

If you deploy using container images, you must update your Dockerfile.

If you don't have a Dockerfile in your project, you can skip this section.

Since Bref container images have been merged into a single bref/php-xx image, the following images don't exist anymore: bref/php-xx-fpm and bref/php-xx-console.

Option 1: Set BREF_RUNTIME in the Dockerfile

The simplest upgrade path is to update your Dockerfile to use the unified image and set the runtime:

Dockerfile
- FROM bref/php-84-fpm:2
+ FROM bref/php-84:3
+ ENV BREF_RUNTIME=fpm
 
# ...

Replace fpm with function or console depending on your use case.

Option 2: Use one image for all function types (recommended)

A major benefit of v3 is that you can now use a single Docker image for all your functions (web, console, queues, etc.) and set BREF_RUNTIME per function in serverless.yml.

Dockerfile (single image for everything):

Dockerfile
FROM bref/php-84:3
 
# Your application code
COPY . /var/task
 
# No BREF_RUNTIME set here!

serverless.yml (set runtime per function):

serverless.yml
functions:
    web:
        image:
            name: my-app-image
        environment:
            BREF_RUNTIME: fpm  # Web/HTTP function
        events:
            - httpApi: '*'
 
    console:
        image:
            name: my-app-image
        environment:
            BREF_RUNTIME: console  # Console commands
 
    worker:
        image:
            name: my-app-image
        environment:
            BREF_RUNTIME: function  # Queue worker
        events:
            - sqs:
                arn: !GetAtt MyQueue.Arn

This approach lets you build and deploy a single Docker image for all function types, simplifying your deployment pipeline.

Local development images

If you use the bref/php-84-fpm-dev image for local development, update it to:

docker-compose.yml
- FROM bref/php-84-fpm-dev:2
+ FROM bref/php-84-dev:3

You can then set BREF_RUNTIME environment variable in your docker-compose.yml file or in the Dockerfile directly.

Smaller breaking changes that might impact you

The changes below should not impact the majority of users. However, if you are using any of these features, you might need to update your code.

Changed the AWS account ID for AWS Lambda layers

The AWS account ID where Bref layers are published is different for v3. That lets us keep releasing Bref v2 layers without mixing up layer numbers. If you reference the layers via their full ARN, you must update the Bref AWS account number to 873528684822 (instead of 534081306603).

# Bref v2 layer
arn:aws:lambda:us-east-1:534081306603:layer:php-84:xxx
 
# Bref v3 layer
arn:aws:lambda:us-east-1:873528684822:layer:php-84:xxx

If you don't know what that means, you're likely not concerned by this change.

If you're not sure, search for 534081306603 in your codebase and replace it with the new account ID.

AWS Lambda layers have been merged into a single layer

If you configure the runtime in your functions using the following syntax:

serverless.yml
functions:
    web:
        # ...
        runtime: php-84-fpm # or `php-xx` or `php-xx-console`

you have nothing to do, your configuration is valid for Bref v3.

However, if you specify AWS Lambda layers explicitly in serverless.yml (or through any other deployment method), for example:

serverless.yml
functions:
    web:
        # ...
        runtime: provided.al2
        layers:
            - ${bref:layer.php-84}
            # or:
            - ${bref:layer.php-84-fpm}
        # or:
        layers:
            - 'arn:aws:lambda:us-east-1:534081306603:layer:php-84:21'

Then you must update your configuration.

Under the hood, all layers have been merged into one, i.e. php-xx-fpm and php-xx-console have been merged into php-xx to make Bref layers simpler. The runtime is now defined via an environment variable that is automatically injected by Bref when using the runtime: syntax.

  • Option 1: switch to using the simpler runtime: syntax.

    Before:

    serverless.yml
    functions:
        web:
            # ...
            runtime: provided.al2
            layers:
                - ${bref:layer.php-84}
                # or:
                - ${bref:layer.php-84-fpm}
                # or:
                - ${bref:layer.php-84-console}

    After:

    serverless.yml
    functions:
        web:
            # ...
            runtime: php-84
            # or:
            runtime: php-84-fpm
            # or:
            runtime: php-84-console

    The examples above assume you are using PHP 8.4 (php-84) but you can replace 84 with another PHP version.

    If you include additional layers, you can keep them without issues, for example:

    serverless.yml
    functions:
        web:
            # ...
            runtime: php-84-fpm
            layers:
                - ${bref-extra:imagick-php-84}
  • Option 2: change the layer names and define the BREF_RUNTIME environment variable.

    Before:

    serverless.yml
    functions:
        web:
            # ...
            runtime: provided.al2
            layers:
                - ${bref:layer.php-84}
                # or:
                - ${bref:layer.php-84-fpm}
                # or:
                - ${bref:layer.php-84-console}

    After:

    serverless.yml
    functions:
        web:
            # ...
            runtime: provided.al2
            layers:
                - ${bref:layer.php-84}
            environment:
                # ...
                BREF_RUNTIME: function # for ${bref:layer.php-xx}
                # or
                BREF_RUNTIME: fpm # for ${bref:layer.php-xx-fpm}
                # or
                BREF_RUNTIME: console # ${bref:layer.php-xx-console}

    The examples above assume you are using PHP 8.4 (php-84) but you can replace 84 with another PHP version.

The vendor/bin/bref CLI has been removed

The vendor/bin/bref CLI has been completely removed in Bref 3.0. This is a minor change since the CLI was already 90% removed in Bref 2.0 - only the bref init command remained for bootstrapping new projects.

We now have better onboarding with improved documentation. Here are the alternatives:

The hooks system has been removed

The deprecated hooks system has been removed. This change affects very few users (less than 1%) as it was a low-level API used primarily by framework integrations.

If you were using Bref::beforeStartup() or Bref::beforeInvoke(), you must migrate to the BrefEventSubscriber pattern:

Before:

use Bref\Bref;
 
Bref::beforeStartup(function () {
    // Setup code
});

After:

use Bref\Bref;
use Bref\Listener\BrefEventSubscriber;
 
class MyEventSubscriber extends BrefEventSubscriber
{
    public function beforeStartup(): void
    {
        // Setup code
    }
}
 
Bref::events()->subscribe(new MyEventSubscriber());

The BrefEventSubscriber class provides additional hooks: afterStartup(), beforeInvoke(), and afterInvoke(). This refactor powers better integrations like the Laravel bridge (opens in a new tab), X-Ray integration (opens in a new tab), and Sentry integration (opens in a new tab).

SOAP extension is now disabled by default

The SOAP PHP extension is now disabled by default. It had very little usage, and disabling it helped reduce layer sizes to make room for more commonly used extensions.

If you need the SOAP extension, you can enable it by creating a php.ini file in your project:

php/conf.d/soap.ini
extension=soap

And reference it in your serverless.yml:

serverless.yml
provider:
    environment:
        BREF_AUTOLOAD_PATH: php/conf.d

Laravel version compatibility

If you are using Laravel with Bref, note that:

  • Laravel 10, 11, or 12 is required (Laravel 8 and 9 are no longer supported).
  • Update bref/laravel-bridge to the latest version.

The Laravel bridge has been updated to use the new BrefEventSubscriber pattern internally, but this change is transparent to users.

CloudWatch log formatter enabled by default

The Bref Monolog formatter (opens in a new tab) is now enabled by default in the Laravel and Symfony bridges.

This changes how your logs will look. Logs now use a hybrid format that combines human-readable text with structured JSON:

Before (plain text):

[2025-12-05 10:30:45] production.ERROR: Database connection failed

After (structured format):

ERROR Database connection failed {"message":"Database connection failed","level":"ERROR","context":{...}}

This format makes logs easier to read in CloudWatch and enables powerful filtering with CloudWatch Logs Insights (e.g., filter by log level or exception class).

Exception handling is greatly improved: Previously, exception stack traces were split across multiple CloudWatch log records (one per line), making them difficult to read and browse. Now, the entire exception (including stack trace) is grouped in a single JSON object, making debugging much easier.

If you prefer the old format, you can disable the formatter in your Laravel or Symfony configuration. See the Bref Monolog documentation (opens in a new tab) for details.

Locale files from glibc langpacks are no longer included

If you are using intl / ICU (opens in a new tab) for locale-aware formatting (dates, numbers, currencies) or translations, you don't need to do anything as ICU is fully supported in Bref v3. Modern frameworks (Laravel, Symfony…) use ICU, not gettext. That means most users are not affected.

If you are using PHP's native gettext (opens in a new tab) functions or rely on setlocale() with specific locales (e.g. for strftime()), glibc locale files are no longer included in Amazon Linux 2023 (AL2023). These will no longer work in Bref v3. You may either:

  • Switch to using intl / ICU, which is the modern standard for translations in PHP and is fully supported in Bref v3.
  • Or, if you want to keep using gettext or setlocale(), switch to container deployments and use a custom Docker image that includes the necessary locale files:
Dockerfile
# Install the locale packages you need (e.g. English and French)
RUN microdnf update -y && \
    microdnf install -y glibc-langpack-en glibc-langpack-fr && \
    microdnf clean all

That's it! Read the Bref 3.0 release announcement to learn more about all the new features and improvements in this release.