Dev Containers and Docker-Based Workspaces in PhpStorm
AI generated
IDE
{ }
PhpStorm · Dev Container · Docker · Remote Development
Dev Containers and Docker-Based
Workspaces in PhpStorm

Reproducible development environments are not a luxury, they are a prerequisite for stable teams and reliable CI results. Dev Containers and Docker-based workspaces in PhpStorm combine containerized environments with full IDE comfort: autocompletion, navigation, debugging and refactoring run inside the container, while the editor stays local.

15 min read devcontainer.json · Remote Dev · Docker Compose · Interpreter PhpStorm 2024.x · Docker · PHP 8.x · Magento 2

1. Dev Container vs. Docker interpreter: making the right choice

PhpStorm offers two fundamentally different ways to integrate Docker into the development workflow: the Docker interpreter and the Dev Container. The Docker interpreter approach means PhpStorm runs locally and uses a Docker container as an interpreter only for specific operations, such as PHP execution, Composer, and XDebug. The code lives on the host system, PhpStorm reads and analyzes it locally, and only the execution is delegated to the container.

The Dev Container approach with PhpStorm's Remote Development goes further: the IDE backend (JetBrains IDE Backend) runs directly inside the container. The PhpStorm UI stays local, but indexing, analysis, navigation and execution all happen entirely inside the container, with exactly the same packages, PHP version and configuration as in production. This eliminates "works on my machine" problems entirely, but requires a bit more configuration effort.

For teams the choice is usually clear: if all developers use the same OS and PHP versions are stable, the Docker interpreter is enough. If the team uses mixed operating systems, if different projects need different PHP versions, or if new team members should be onboarded quickly, the Dev Container approach is superior in the long run.

2. Configuring devcontainer.json for PHP projects

The devcontainer.json is the central configuration file for Dev Containers, used by both VS Code and JetBrains IDEs. PhpStorm reads this file automatically when it sits in the project's .devcontainer/ directory. The file defines the container image, ports, mounts, extensions (for VS Code), and features, which are reusable installation scripts for common tools.

For PHP projects the most important fields are: image or dockerComposeFile for the base image, postCreateCommand for setup steps after the container starts (e.g. composer install), and forwardPorts for port forwarding. PhpStorm recognizes customizations.jetbrains inside devcontainer.json for IDE-specific settings, such as which plugins should be installed automatically.

Features are predefined, composable installation blocks: ghcr.io/devcontainers/features/php:1 installs PHP with a configurable version. ghcr.io/devcontainers/features/node:1 adds Node.js. ghcr.io/devcontainers/features/docker-in-docker:2 enables Docker commands inside the container itself. These features are versioned and reproducible, a major advantage over manual installation scripts.


// .devcontainer/devcontainer.json for PHP 8.4 / Magento 2 project
{
  "name": "Mironsoft PHP 8.4 Dev",
  "dockerComposeFile": ["../compose.yaml", "docker-compose.devcontainer.yml"],
  "service": "phpfpm",
  "workspaceFolder": "/var/www/html",
  "forwardPorts": [80, 443, 9003],
  "postCreateCommand": "composer install --no-interaction",
  "remoteUser": "app",
  "customizations": {
    "jetbrains": {
      "backend": "PhpStorm",
      "plugins": [
        "com.jetbrains.php",
        "org.jetbrains.plugins.phpstorm-remote-interpreter"
      ]
    }
  },
  "features": {
    "ghcr.io/devcontainers/features/php:1": {
      "version": "8.4",
      "installComposer": true
    },
    "ghcr.io/devcontainers/features/node:1": {
      "version": "22"
    }
  },
  "mounts": [
    "source=${localWorkspaceFolder}/src,target=/var/www/html,type=bind"
  ]
}

3. PhpStorm Remote Development: the IDE backend inside the container

PhpStorm's Remote Development feature (since 2022.3) lets you run the IDE backend, the server part of the IDE responsible for indexing and analysis, directly inside a Docker container or on a remote server. The client part (UI) stays local. The connection happens over SSH or directly via Docker.

Getting started: "File > Remote Development > Dev Containers > Open" or via the Gateway window. PhpStorm detects devcontainer.json files in the current project and offers to start the container and install the IDE backend inside it. On the first run PhpStorm downloads the JetBrains IDE Backend package into the container, which takes a few minutes but happens automatically on subsequent updates.

Once started, the IDE behaves identically to a local installation: all shortcuts work, all tool windows are available, and static analysis runs on the container's files. The difference: Ctrl+Click on a class navigates to the container filesystem version of the file, XDebug connects directly to the container's PHP process, and Composer runs against the container PHP. For a Magento project this means PhpStorm indexes the actual Magento source files inside the container, with the exact PHP version and all installed extensions.

4. Setting up the PHP interpreter and tools inside the container

Even without full Remote Development, the PHP interpreter can point at a Docker container. Under "Settings > PHP > CLI Interpreter > Add > Docker / Docker Compose" you select the service from docker-compose.yml (e.g. phpfpm) and the PHP path inside the container. PhpStorm connects to the container when the dialog opens and reads the available interpreters automatically.

With the Docker interpreter set as the PHP interpreter, the following also work automatically: PHPUnit (tests run inside the container), PHPStan (analysis runs inside the container with the packages found there), PHP CS Fixer and PhpCS (formatting according to the container configuration), and XDebug (if configured in the container). The developer does not need to install any tools locally, everything comes from the container.

A practical note for Magento: the generated/ folder in the Magento root contains automatically generated classes (interceptors, factories). These only exist after running bin/magento setup:di:compile, i.e. after an action inside the container. When PhpStorm accesses the container files directly (Remote Development), these classes are immediately navigable. With local access via the Docker interpreter, the generated/ folder must be marked as a library root so PhpStorm indexes it.


# docker-compose.devcontainer.yml, extends compose.yaml for Dev Container
version: '3.9'
services:
  phpfpm:
    # Add dev-only tools not needed in production
    build:
      context: .
      dockerfile: Dockerfile.dev
    environment:
      XDEBUG_MODE: "develop,debug"
      XDEBUG_CONFIG: "client_host=host.docker.internal client_port=9003"
      PHP_IDE_CONFIG: "serverName=mironsoft-local"
    volumes:
      # Persist Composer cache between container rebuilds
      - composer_cache:/root/.composer/cache
      # Mount SSH keys for private Composer repositories
      - ${HOME}/.ssh:/root/.ssh:ro
    ports:
      - "9003:9003"  # XDebug

volumes:
  composer_cache:

# PhpStorm: Settings > PHP > CLI Interpreter > Add > Docker Compose
#   Service: phpfpm
#   PHP executable: /usr/local/bin/php
#   Detected: PHP 8.4.x with Xdebug 3.x

5. Dev Container for Magento 2 with the Mark Shust stack

The Mark Shust stack for Magento (docker-magento) already ships with all necessary services: phpfpm, nginx, db (MySQL), redis, elasticsearch and optionally rabbitmq. A Dev Container for this setup extends the existing Compose files with a specific devcontainer.json and a docker-compose.devcontainer.yml that overrides dev-specific settings without touching the production stack.

Important adjustments for the Magento Dev Container setup: the phpfpm service needs XDebug (not included in production images), SSH keys for Composer (private Adobe Commerce packages), and an increased PHP memory limit for running the IDE backend. The workspaceFolder in devcontainer.json points to /var/www/html, the Magento root inside the container.

Once the Dev Container starts, PhpStorm automatically begins indexing. For a Magento project with 30,000+ PHP files (core, modules, vendor), the first indexing pass takes 10 to 20 minutes. After that it is cached inside the container and updated incrementally on filesystem changes. For better performance it is worth marking generated/, var/ and pub/static/ as excluded directories, since these contain no navigable source files and unnecessarily lengthen indexing time.

6. Configuring XDebug inside the Dev Container

XDebug inside a Dev Container requires a bit more configuration effort than a local setup, because PhpStorm and PHP run in different network namespaces. The XDebug client (PhpStorm) is on the host, the XDebug server (PHP) is inside the container. The connection has to go from the container to the host, which happens via host.docker.internal on macOS and Windows, or via the host gateway IP on Linux.

The critical XDebug settings inside the container: xdebug.client_host=host.docker.internal (or the gateway IP), xdebug.client_port=9003, xdebug.mode=debug and xdebug.start_with_request=yes for automatic debugging without a browser extension. In PhpStorm, port 9003 must be configured under "Settings > PHP > Debug". Under "Settings > PHP > Servers" a server is created with the name from PHP_IDE_CONFIG=serverName=..., along with path mappings between host paths and container paths.

Path mappings are the most common stumbling block: PhpStorm sees the files under the host path (e.g. /home/user/project/src), while PHP runs them under the container path (e.g. /var/www/html). Without a correct mapping, PhpStorm cannot match XDebug breakpoints to the right files. With Remote Development this problem disappears entirely, since PhpStorm works directly with the container paths.


<?php
// XDebug configuration in php.ini / conf.d/xdebug.ini (inside container)
// zend_extension=xdebug
// xdebug.mode=develop,debug
// xdebug.client_host=host.docker.internal
// xdebug.client_port=9003
// xdebug.start_with_request=yes
// xdebug.log=/tmp/xdebug.log
// xdebug.log_level=7

// PhpStorm: Settings > PHP > Servers > Add
//   Name: mironsoft-local  (must match PHP_IDE_CONFIG serverName)
//   Host: localhost
//   Port: 80
//   Debugger: XDebug
//   Path mappings:
//     /home/mir/development/mironsoft/src -> /var/www/html

// Verify connection: Run > Start Listening for PHP Debug Connections
// Then: curl http://localhost/health
// PhpStorm should show "Incoming connection from XDebug" dialog

// Common issue: Linux host.docker.internal not available
// Solution: add to docker-compose.devcontainer.yml:
//   extra_hosts:
//     - "host.docker.internal:host-gateway"

7. Sharing and standardizing Dev Containers across a team

The biggest benefit of Dev Containers for teams is reproducibility: the devcontainer.json is checked into the repository and available to every developer. A new team member clones the repository, opens it in PhpStorm, confirms "Reopen in Container", and has a fully configured development environment within a few minutes. No manual PHP installation, no local Magento setup, no "works on my machine but not on yours" discussions.

For team standardization it is worth extending devcontainer.json with the following elements: postCreateCommand for composer install and initial Magento configuration, postStartCommand for services that need to be initialized on every container start, and waitFor to control the order of initialization steps. Environment variables for secrets (API keys, database passwords) come from .env files that are not checked into the repository.

A well-structured Dev Container setup for Magento contains: the devcontainer.json in the repository, a separate docker-compose.devcontainer.yml that extends the production Compose file, a Dockerfile.dev with dev-specific tools (XDebug, Composer, shell tools), and a .devcontainer/setup.sh script for the postCreateCommand. The setup script runs composer install, bin/magento setup:upgrade and other initialization steps once, right after the container build.

8. Comparison: Dev Container approaches at a glance

Aspect Docker interpreter Remote Dev (Gateway) Recommendation
IDE performance Local, fast Depends on container hardware Docker interpreter for strong local machines
Environment consistency Analysis local, execution in container 100% in container Remote Dev for consistency
Path mappings Manual configuration Automatic (container paths) Remote Dev for XDebug
Onboarding effort Interpreter configuration per developer devcontainer.json is enough Remote Dev for teams
Setup complexity Low devcontainer.json + Compose Worth a one-time investment

Mironsoft

Docker setups, Magento 2 and PhpStorm infrastructure

Set up Dev Containers for your PHP team?

We build reproducible Dev Container setups for Magento and PHP projects, from devcontainer.json all the way to full PhpStorm integration with XDebug.

Dev Container setup

devcontainer.json, Docker Compose, Dockerfile.dev for Magento and PHP projects

IDE configuration

Configuring PhpStorm Remote Development, interpreters, and XDebug path mappings

Team onboarding

Onboarding documentation and setup scripts for new team members

9. Summary

Dev Containers and Docker-based workspaces in PhpStorm solve the fundamental problem of development environment inconsistency. The devcontainer.json defines the environment declaratively and reproducibly, checked into the repository and available to every developer. PhpStorm's Remote Development brings the IDE backend directly into the container, so indexing, analysis and navigation all work with the exact container packages and the exact container PHP version.

For Magento projects using the Mark Shust stack the approach is clear: existing Compose files are extended with a docker-compose.devcontainer.yml, XDebug is configured for container-to-host connections, and devcontainer.json defines a postCreateCommand for automatic initialization. The result: new team members are productive in under 30 minutes, without manual PHP installation or a local Magento setup. Works on every machine, because the machine is the container.

Dev Containers in PhpStorm: the essentials at a glance

devcontainer.json

Check .devcontainer/devcontainer.json into the repository. Use features for PHP, Node, and Docker-in-Docker. postCreateCommand for composer install and Magento setup.

Remote Development

File > Remote Development > Dev Containers. IDE backend runs inside the container. No path mapping problems, no version conflicts between host and container.

XDebug in the container

client_host=host.docker.internal (Linux: extra_hosts: host.docker.internal:host-gateway). Server name in PHP_IDE_CONFIG must match the server name in PhpStorm settings.

Team onboarding

devcontainer.json in the repo plus Dockerfile.dev plus docker-compose.devcontainer.yml. New developers: clone the repository, confirm "Reopen in Container", wait.

10. FAQ: Dev Containers and Docker-Based Workspaces in PhpStorm

1Docker interpreter vs. Dev Container?
Docker interpreter: PhpStorm local, PHP in the container. Dev Container: IDE backend in the container. Dev Container means more consistency, Docker interpreter means a simpler setup. For teams, Dev Container is recommended.
2What is devcontainer.json?
Configuration file for Dev Containers in the .devcontainer/ directory. Check it into the repository. PhpStorm and VS Code read it automatically. Defines image, features, ports, mounts, postCreateCommand.
3Starting a Dev Container in PhpStorm?
File > Remote Development > Dev Containers > Open. PhpStorm detects devcontainer.json, starts the container, installs the IDE backend. After that: a full IDE inside the container.
4Fixing XDebug path mapping problems?
Settings > PHP > Servers: create a server, configure path mappings from host path to container path. With Remote Development this step disappears entirely.
5Speeding up indexing for a Magento project?
Mark generated/, var/, and pub/static/ as excluded directories. First run takes 10 to 20 minutes, then incremental. After that it is cached.
6What are Dev Container Features?
Composable installation blocks: ghcr.io/devcontainers/features/php:1, node:1, docker-in-docker:2. Versioned, reproducible, community-maintained. Better than manual installation scripts.
7host.docker.internal on Linux?
Not available automatically. Solution: add extra_hosts in docker-compose.devcontainer.yml: "host.docker.internal:host-gateway". Then XDebug client_host=host.docker.internal.
8Can Dev Containers be used offline?
Yes, after the first download of the image and the IDE backend. Both are cached. Offline development is fully possible afterward.
9Sharing secrets in a Dev Container?
Keep .env files local, do not check them in. Check in a .env.example with placeholders. devcontainer.json: runArgs ['--env-file', '.env'] for automatic loading.
10Remote Development on SSH servers?
Yes, File > Remote Development > SSH. The IDE backend is installed on the remote server. Useful for cloud VMs or dedicated development servers.