Skip Navigation
Show nav
Dev Center
  • Get Started
  • Documentation
  • Changelog
  • Search
  • Get Started
    • Node.js
    • Ruby on Rails
    • Ruby
    • Python
    • Java
    • PHP
    • Go
    • Scala
    • Clojure
    • .NET
  • Documentation
  • Changelog
  • More
    Additional Resources
    • Home
    • Elements
    • Products
    • Pricing
    • Careers
    • Help
    • Status
    • Events
    • Podcasts
    • Compliance Center
    Heroku Blog

    Visit the Heroku Blog

    Find news and updates from Heroku in the blog.

    Visit Blog
  • Log inorSign up
Hide categories

Categories

  • Heroku Architecture
    • Compute (Dynos)
      • Dyno Management
      • Dyno Concepts
      • Dyno Behavior
      • Dyno Reference
      • Dyno Troubleshooting
    • Stacks (operating system images)
    • Networking & DNS
    • Platform Policies
    • Platform Principles
  • Developer Tools
    • Command Line
    • Heroku VS Code Extension
  • Deployment
    • Deploying with Git
    • Deploying with Docker
    • Deployment Integrations
  • Continuous Delivery & Integration (Heroku Flow)
    • Continuous Integration
  • Language Support
    • Node.js
      • Node.js Behavior in Heroku
      • Working with Node.js
      • Troubleshooting Node.js Apps
    • Ruby
      • Rails Support
      • Working with Bundler
      • Working with Ruby
      • Ruby Behavior in Heroku
      • Troubleshooting Ruby Apps
    • Python
      • Working with Python
      • Background Jobs in Python
      • Python Behavior in Heroku
      • Working with Django
    • Java
      • Java Behavior in Heroku
      • Working with Java
      • Working with Maven
      • Working with Spring Boot
      • Troubleshooting Java Apps
    • PHP
      • Working with PHP
      • PHP Behavior in Heroku
    • Go
      • Go Dependency Management
    • Scala
    • Clojure
    • .NET
      • Working with .NET
  • Databases & Data Management
    • Heroku Postgres
      • Postgres Basics
      • Postgres Getting Started
      • Postgres Performance
      • Postgres Data Transfer & Preservation
      • Postgres Availability
      • Postgres Special Topics
      • Migrating to Heroku Postgres
    • Heroku Key-Value Store
    • Apache Kafka on Heroku
    • Other Data Stores
  • AI
    • Heroku Inference
      • AI Models
      • Inference Essentials
      • Inference API
      • Quick Start Guides
    • Working with AI
    • Vector Database
  • Monitoring & Metrics
    • Logging
  • App Performance
  • Add-ons
    • All Add-ons
  • Collaboration
  • Security
    • App Security
    • Identities & Authentication
      • Single Sign-on (SSO)
    • Private Spaces
      • Infrastructure Networking
    • Compliance
  • Heroku Enterprise
    • Enterprise Accounts
    • Enterprise Teams
    • Heroku Connect (Salesforce sync)
      • Heroku Connect Administration
      • Heroku Connect Reference
      • Heroku Connect Troubleshooting
  • Patterns & Best Practices
  • Extending Heroku
    • Platform API
    • App Webhooks
    • Heroku Labs
    • Building Add-ons
      • Add-on Development Tasks
      • Add-on APIs
      • Add-on Guidelines & Requirements
    • Building CLI Plugins
    • Developing Buildpacks
    • Dev Center
  • Accounts & Billing
  • Troubleshooting & Support
  • Integrating with Salesforce
  • Language Support
  • PHP
  • Working with PHP
  • Managing PHP Extensions

Managing PHP Extensions

Last updated March 17, 2025

Table of Contents

  • Using Optional Extensions
  • Treatment of Extensions “Provided” by Userland Packages

Heroku offers a variety of built-in and third-party extensions that you can use in your PHP applications. You can also use optional extensions for your app. This article shows how you can declare optional extensions.

Using Optional Extensions

You can declare any optional extensions you want to use via composer.json using Composer Platform Packages; simply prefix any of the identifiers in the list of extensions above with “ext-” in the package name.

For example, to enable the optional bundled extensions bcmath and GMP, together with the third-party Memcached, and a version of the third-party MongoDB:

{
    "require": {
        "ext-bcmath": "*",
        "ext-gmp": "*",
        "ext-memcached": "*",
        "ext-mongodb": "^1.19.0"
    }
}

It’s recommended that you use “*” as the version selector when specifying extensions that are bundled with PHP, as their version numbers can be highly inconsistent (they often report their version as “0”).

Next, ensure that your new requirements are “frozen” to composer.lock by running:

$ composer update

Finally, don’t forget to git add and git commit both files!

If you don’t have the desired extension available locally on your computer, the composer update step fails because the requirements in composer.json can’t be satisfied. If you can’t install the missing extension on your computer using pecl, brew, or similar methods (something you absolutely should do in the interest of maintaining dev/prod parity), you can instruct composer to ignore the missing ( “platform”) requirements:

$ composer update --ignore-platform-reqs

You can use the same --ignore-platform-reqs flag when running composer install on subsequent dependency installations in new environments, for example on other developers’ computers, where the extension is similarly unavailable.

Upon the next push, Heroku installs and enables the corresponding PHP extensions:

-----> Installing platform packages...
       - php (8.2.13)
       - ext-bcmath (bundled with php)
       - ext-mcrypt (bundled with php)
       - ext-mongodb (1.17.0)
       - ext-memcached (3.2.0)
       - apache (2.4.58)
       - nginx (1.24.0)

Any PHP extension required by a dependency of a project pushed to Heroku is installed automatically, as the list of extensions to be installed is read from composer.lock.

For example, if a project depends on the stripe/stripe-php PHP SDK for Stripe, the mbstring extension required by the Stripe SDK will automatically be installed upon deploy, without the ext-mbstring package having to be listed explicitly in the require section of your main composer.json.

Treatment of Extensions “Provided” by Userland Packages

Composer packages like Symfony Polyfills declare a native PHP extension as provide in their package metadata, and implement the functionality of that extension, partially or completely, purely using PHP code. This causes Composer to consider them a possible replacement of the real, native PHP extension during the resolution of dependencies.

During a build, these “polyfill” declarations are honored by Heroku when installing platform packages, using the exact same rules that Composer applies to the installation of packages.

This means that a requirement of composer.json, or any dependency, such as ext-mbstring doesn’t lead to the installation of the native ext-mbstring extension if the symfony/polyfill-mbstring package is also present in composer.lock, as symfony/polyfill-mbstring declares ext-mbstring as provided:

-----> Installing platform packages...
       - php (8.1.2)
       - apache (2.4.52)
       - composer (2.2.5)
       - nginx (1.20.2)

For maximum performance and compatibility, after the initial resolving of platform package dependencies have finished, Heroku’s PHP support then attempts to install native versions of all extensions that userland packages have declared as provide:

-----> Installing platform packages...
       - php (8.1.2)
       - apache (2.4.52)
       - composer (2.2.5)
       - nginx (1.20.2)
       NOTICE: detected userland polyfill packages for PHP extensions
       NOTICE: now attempting to install native extension packages
       Installing extensions provided by symfony/polyfill-mbstring:
       - ext-mbstring (bundled with php)

These installation attempts aren’t always successful, like if the extension isn’t available on Heroku, or for the selected PHP version:

-----> Installing platform packages...
       - php (8.1.2)
       - apache (2.4.52)
       - composer (2.2.5)
       - nginx (1.20.2)
       NOTICE: detected userland polyfill packages for PHP extensions
       NOTICE: now attempting to install native extension packages
       Installing extensions provided by phpseclib/mcrypt_compat:
       NOTICE: no suitable native version of ext-mcrypt available

No changes are made to platform packages that have already resolved. If a native variant isn’t available for the installed PHP version, no downgrade to a PHP version is performed, even if that lower PHP version is permitted by all other dependencies.

This behavior ensures that userland polyfill packages can correctly serve their purpose where necessary, like when acting as a replacement for an extension that is no longer bundled with PHP (for example phpseclib/mcrypt_compat does for ext-mcrypt in the example above), while simultaneously ensuring that the native PHP extension in question is installed whenever possible for maximum performance and compatibility.

Keep reading

  • Working with PHP

Feedback

Log in to submit feedback.

Uploading Files to S3 in PHP Managing PHP Web Servers

Information & Support

  • Getting Started
  • Documentation
  • Changelog
  • Compliance Center
  • Training & Education
  • Blog
  • Support Channels
  • Status

Language Reference

  • Node.js
  • Ruby
  • Java
  • PHP
  • Python
  • Go
  • Scala
  • Clojure
  • .NET

Other Resources

  • Careers
  • Elements
  • Products
  • Pricing
  • RSS
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku Blog
    • Heroku News Blog
    • Heroku Engineering Blog
  • Twitter
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku
    • Heroku Status
  • Github
  • LinkedIn
  • © 2025 Salesforce, Inc. All rights reserved. Various trademarks held by their respective owners. Salesforce Tower, 415 Mission Street, 3rd Floor, San Francisco, CA 94105, United States
  • heroku.com
  • Legal
  • Terms of Service
  • Privacy Information
  • Responsible Disclosure
  • Trust
  • Contact
  • Cookie Preferences
  • Your Privacy Choices