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
      • Working with Node.js
      • Node.js Behavior in Heroku
      • 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
      • PHP Behavior in Heroku
      • Working with PHP
    • 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
    • Working with AI
    • Heroku Inference
      • Inference API
      • Quick Start Guides
      • AI Models
      • Inference Essentials
    • Vector Database
    • Model Context Protocol
  • 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
  • PHP Behavior in Heroku
  • PHP Behavior in Heroku

PHP Behavior in Heroku

Last updated March 17, 2025

Table of Contents

  • Auto-Detection
  • PHP Runtimes
  • Customizing Settings
  • Build Behavior
  • Customer Support
  • Additional Reading

The Heroku Platform uses the PHP buildpack to handle deployed PHP applications. The following shows Heroku’s behavior towards PHP apps and how it recognizes, runs, and builds them.

Auto-Detection

Heroku PHP support applies to applications that have a file named composer.json in the root directory. Even if an application has no Composer dependencies, it must include at least an empty ({}) composer.json in order to be recognized as a PHP application.

When Heroku recognizes a PHP application, it responds accordingly during a push:

$ git push heroku main
-----> PHP app detected
…

If composer.json specifies dependencies of any kind in its require section, the corresponding composer.lock that gets generated by running composer update must also be committed to the repository, or the push is rejected. This ensures that the dependencies Heroku installs are the same as in any other environment. For detailed instructions, check out the “Manage Dependencies” section of the Deploying PHP guide.

PHP Runtimes

Heroku allows you to run your application using the official PHP runtime. To learn how to specify a PHP runtime, refer to the corresponding Dev Center article.

Runtime Settings

All PHP runtimes use the respective release’s php.ini-production file as their base php.ini configuration.

Notwithstanding the above, the following INI directives are set to Heroku-specific values:

  • date.timezone is set to UTC
  • error_reporting is set to
    • E_ALL & ~E_STRICT for PHP versions before 8.4
    • E_ALL for PHP 8.4 or later
  • expose_php is set to Off
  • session.sid_length is set to 32 (for PHP versions 7.3 to 8.3)
  • short_open_tag is set to On
  • user_ini.cache_ttl is set to 86400
  • variables_order is set to EGPCS

In addition, the PHP runtimes always have OPcache enabled for improved performance, with the following configuration changes optimized for the specific characteristics of Heroku’s dynos:

  • opcache.enable_cli is set to 1
  • opcache.validate_timestamps is set to 0

PHP CLI

The memory_limit PHP INI directive for the php CLI executable defaults to the full available dyno memory. For example, worker dynos using a php command use this memory limit instead of the default PHP INI value of 128M.

Default Runtime

Applications that don’t use a composer.json, or where composer.lock contains no requirements for package php even in any dependent package, will receive the latest version of PHP that is available on the app’s stack.

Upgrades

If you deploy an application that doesn’t declare a runtime version dependency, the then-latest version of PHP is used. Your application upgrades to more recent versions of PHP if available automatically upon the next deployment.

If your application declares runtime version dependencies, the most recent version matching the version constraint will be selected for installation.

Runtime Behavior

The $PATH environment variable contains all necessary paths for an application to function at runtime. The Composer bin-dir is appended to $PATH for convenience.

PHP-FPM Configuration

PHP-FPM is set up to automatically spawn a suitable number of worker processes depending on dyno size and the configured PHP memory_limit. For more information, see Optimizing PHP Application Concurrency.

Timeouts

When a request reaches the Heroku router’s request timeout, a PHP-FPM process continues to run, potentially as long as it takes for example an external timeout to occur. This would tie up that PHP-FPM process, which could then no longer respond to other incoming requests.

For applications using PHP 7.4 or later, by default, PHP-FPM will therefore

  • log a backtrace of requests that take longer than three seconds (request_slowlog_timeout directive), and
  • terminate requests that have exceeded an execution time of 30 seconds (request_terminate_timeout directive) and therefore likely timed out.

You may adjust the settings for PHP-FPM to change these (or other) configuration settings.

Composer Configuration

For convenience, the following settings for Composer are automatically set using environment variables:

  • $COMPOSER_MEMORY_LIMIT defaults to the available dyno memory;
  • $COMPOSER_MIRROR_PATH_REPOS defaults to 1;
  • $COMPOSER_NO_INTERACTION defaults to 1;
  • $COMPOSER_PROCESS_TIMEOUT defaults to 0.

Customizing Settings

PHP

Any .user.ini file that’s placed into a project according to the instructions in the PHP manual loads after the main php.ini. You can use these to set any directive permitted in PHP_INI_ALL, PHP_INI_USER and PHP_INI_PERDIR contexts.

For additional details on this and other ways of customizing settings for the PHP runtime, refer to the corresponding Dev Center article.

Build Behavior

Installation of Dependencies

The following command is run during a deploy to resolve dependencies unless composer.json is empty and no composer.lock is present:

$ composer install --no-dev --prefer-dist --optimize-autoloader --no-interaction

Heroku won’t install development dependencies from the require-dev section of composer.json. However, if the require-dev section contains a PHP runtime version requirement or lists a dependency that contains such a requirement, then the require section of composer.json must also contain a PHP runtime version requirement or list a dependency that contains such a requirement. This is to ensure that Heroku doesn’t select a default PHP runtime version that conflicts with what other environments (which include require-dev dependencies) install.

The installed version of Composer will be printed for your reference before installation begins. Builds are run using the latest possible Composer version (1.x, 2.2.x LTS, or 2.3+) that’s compatible with an application’s composer.lock. The respective version of Composer is available on $PATH at app runtime under the command name composer.

An application’s Composer cache directory is persisted between builds to speed up package installation on subsequent deploys.

Custom Compile Step

For applications that wish to execute an additional compilation step during a build that shouldn’t be part of a standard post-install-cmd Composer script, for example an asset compilation or cache pre-warming procedure, a compile custom command, if present in composer.json, executes using the following command:

$ composer compile --no-dev --no-interaction

Any such custom script command defined in composer.json can either be a single string, or an array of multiple commands to execute; example:

{
  "scripts": {
    "compile": [
      "@php app/console assetic:dump --env=prod --no-debug",
      "MyVendor\\MyClass::postDeployComposerCallback"
    ]
  }
}

If you must execute php or composer in any Composer script, always reference the executables using the @php or @composer shorthand notations. This will always call the correct PHP or Composer executable in any environment, and also ensure any Composer configuration, including the right PHP memory_limit, is applied.

 

Composer’s bin-dir is pushed on top of $PATH during command execution, making binaries installed by dependencies easily accessible as CLI commands when writing scripts without having to use vendor/bin/ or a similar prefix.

Private Repositories

To use private repositories like Private Packagist, or packages from a source that requires authentication (such as a private GitHub repository), Composer must be provided with authentication details (typically a token generated by the provider or service).

On a development machine, these are typically stored by Composer in auth.json, but on Heroku, such secrets are stored as environment variables. The COMPOSER_AUTH environment variable is automatically read by Composer; its JSON structure is identical to auth.json.

The following entries are allowed as top-level keys in the JSON document:

  • http-basic
  • github-oauth
  • gitlab-oauth
  • gitlab-token
  • bitbucket-oauth

Each entry then contains a hash of domains as keys and authentication details as values; the authentication detail structure is specific to each of the sources above and described in the documentation.

When using GitHub Enterprise or the Self-Managed version of GitLab, remember to also set the github-domains or gitlab-domains config option inside your project’s composer.json.

For example, to store authentication details for a Private Packagist, account, set the COMPOSER_AUTH variable using heroku config:set with http-basic details (replacing “YOURTOKEN” with the actual token Private Packagist generated):

$ heroku config:set COMPOSER_AUTH='{"http-basic":{"repo.packagist.com":{"username":"token","password":"YOURTOKEN"}}}'

To give another example, when using code from private GitHub repositories as Composer dependencies, a personal OAuth token can be set for authentication. After creating a new Token, you can set it on Heroku (replacing “YOURTOKEN” with the actual token GitHub generated):

$ heroku config:set COMPOSER_AUTH='{"github-oauth":{"github.com":"YOURTOKEN"}}'

The private repository URL in your composer.json must use the https:// and not the git:// protocol for Composer to be able to use the OAuth token for authentication.

Several sets of authentication details can also be combined into a single document; for example, to use both private GitHub and private BitBucket repositories:

$ heroku config:set COMPOSER_AUTH='{
    "github-oauth": {"github.com": "YOURTOKEN"},
    "bitbucket-oauth": {"bitbucket.org": {
        "consumer-key": "YOURKEY", "consumer-secret": "YOURSECRET"}
    }
}'

You may use line breaks within quotes when setting environment variables on Heroku as shown in the example above, but you must ensure that the quoting is correct when running the heroku config:set command.

Customer Support

You can submit issues via one of the Heroku Support channels.

Additional Reading

  • Heroku PHP Support Reference
  • Specifying a PHP Runtime

Keep reading

  • PHP Behavior in Heroku

Feedback

Log in to submit feedback.

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