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

    Heroku Blog

    Find out what's new with Heroku on our 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
      • Troubleshooting Node.js Apps
      • Working with Node.js
      • Node.js Behavior in Heroku
    • 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
    • Vector Database
    • Working with AI
    • Heroku Inference
      • AI Models
      • Inference Essentials
      • Inference API
      • Quick Start Guides
    • 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
  • Deployment
  • Deploying with Docker
  • Local Development with Docker Compose

Local Development with Docker Compose

English — 日本語に切り替える

Last updated October 11, 2024

Table of Contents

  • Introduction to Docker Compose
  • Pushing Your Containers to Heroku
  • Docker Compose Tips and Tricks
  • See Also

Docker Compose is a tool for defining and running a multi-container Docker application. Learn how Docker Compose is great for local development, how you can push your Docker images to Heroku for deployment, and other tips and tricks.

Introduction to Docker Compose

Let’s start out with a simple Python-based multi-container application. This example app consists of Redis, a web frontend for caching, and Postgres as our database. Docker, Redis, and Postgres are each run in a separate container.

You can use Docker Compose to define your local development environment, including environment variables, ports that you need accessible, and volumes to mount. You define everything in docker-compose.yml, which the docker-compose CLI uses.

The docker-compose.yml for the application is:


version: '2'
services:
  web:
    build: .
    ports:
      - "5000:5000"
    env_file: .env
    depends_on:
      - db
    volumes:
      - ./webapp:/opt/webapp
  db:
    image: postgres:latest
    ports:
      - "5432:5432"
  redis:
    image: redis:alpine
    ports:
      - "6379:6379"

The Web Service

The first section defines the web service. It opens port 5000, sets environment variables defined in .env, and mounts our local code directory as a volume.


services:
  web:
    build: .
    ports:
      - "5000:5000"
    env_file: .env
    depends_on:
      - db
    volumes:
      - ./webapp:/opt/webapp

The Database service

The next service is the Postgres database, which opens port 5432 and uses the latest official Postgres image on Docker Hub.

db:
    image: postgres:latest
    ports:
      - "5432:5432"

The Redis Service

This section defines our Redis service, which opens port 6379 and uses the official Redis image on Docker Hub.


 redis:
    image: redis:alpine
    ports:
      - "6379:6379"

Now that you defined the local development environment in docker-compose.yml, you can spin up all three services with one command.

$ docker-compose up

This command confirms that all three containers are running.

$ docker ps
CONTAINER ID        IMAGE                COMMAND
8e422ff92239        python_web           "/bin/sh -c 'python a"
4ac9ecc8a2a3        python_db            "/docker-entrypoint.s"
2cbc8febd074        redis:alpine         "docker-entrypoint.sh"

The Benefits of Docker Compose

Using Docker and defining your local development environment with Docker Compose provides several benefits:

  • By running Redis and Postgres in a Docker container, you don’t install or maintain the software on your local machine.
  • You can check your entire local development environment into source control, making it easier for other developers to collaborate on a project.
  • You can spin up the entire local development environment with one command: docker-compose up.

Pushing Your Containers to Heroku

When you’re satisfied with the build, you can push the web frontend directly to the Heroku container registry for deployment. We also support popular CI/CD tools.

$ heroku container:push web

The Python application depends on Postgres and Redis, which you don’t push to Heroku. Instead, use Heroku add-ons in production.

Use Heroku Add-ons in Production

  • For local development: Use official Docker images, such as Postgres and Redis.
  • For staging and production: Use Heroku add-ons, such as Heroku Postgres and Heroku Key-Value Store.

Using official Docker images locally and Heroku add-ons in production provides you with the best of both worlds.

  • Parity: You get parity by using the same services on your local machine as you do in production.
  • Reduced ops burden: By using add-ons, Heroku or the add-on provider takes the ops burden of replication, availability, and backup.

Docker Compose Tips and Tricks

When using Docker Compose for local development, knowing these tips and tricks can help.

Create a .env File to Avoid Checking Credentials Into Source Code Control

By using Docker and Docker Compose, you can check your local development environment setup into source code control. To handle sensitive credentials, create a .env environment file with your credentials and reference it within your Compose YAML. Add your .env to your .gitignore and .dockerignore files, so that it’s not checked into source code control or included in your Docker image.

services:
  web:
    env_file: .env

Mount Your Code as a Volume to Avoid Image Rebuilds

Any time you make a change to your code, you must rebuild your Docker image. This rebuild is a manual, potentially time-consuming step. To solve this issue, mount your code as a volume. Now, rebuilds are no longer necessary when the code changes.

services:
  web:
    volumes:
      - ./webapp:/opt/webapp

Use Hostnames to Connect to Containers

By default, Docker Compose sets up a single network for your app. When you name a service in your Compose YAML, it creates a hostname that you can use to connect to the service.

Our services in Compose YAML:

services:
  web:
  redis:
  db:

Our connection strings:

postgres://db:5432
redis://redis:6379

Running Compose in Background Mode

When you execute docker-compose up, your project runs in the foreground, displaying the output of your services. You can shut down the services gracefully using ctrl+c.

One lesser-known option is to use docker-compose up -d to start your containers in the background. You can tear down the Compose setup using docker-compose down. You check the logs of services running in background mode using docker-compose logs.

Multi-Dockerfile Project Structure

When you have multiple services, we suggest creating a subdirectory for each Docker image in your project, with the Dockerfile stored in each respective directory.

/web/Dockerfile
/redis/Dockerfile
/db/Dockerfile
/worker/Dockerfile

We don’t recommend storing all Dockerfiles in the project home directory because it makes distinguishing between services harder.

Run Your Containers as a Non-Root User

It’s a good security practice to run your containers as a non-root user. Also, containers that you push to Heroku run without root access. By testing your containers locally as a non-root user, you can ensure that they work in your Heroku production environment. Learn more in the container registry documentation.

See Also

  • Official Docker Compose documentation
  • Heroku container registry documentation

Keep reading

  • Deploying with Docker

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