Add tutorial and reference for extends - #1251

Merged
bfirsh merged 1 commit into
docker:masterfrom
aanand:extends-guide
Apr 8, 2015
Merged

Add tutorial and reference for extends#1251
bfirsh merged 1 commit into
docker:masterfrom
aanand:extends-guide

Conversation

@aanand

Copy link
Copy Markdown

Closes#1111 and #1127.

@aanandaanand added this to the 1.2.0 milestone Apr 3, 2015
@bfirsh

Copy link
Copy Markdown

Nice. LGTM

cc @moxiegirl

Comment threaddocs/extends.md

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, there are some awkward constructions in here. Generally, readers use technical documents to perform tasks or gather information. For readers, these activities take place in the present. Therefore, the present tense is appropriate in most cases.

Also the first person plural "We" is awkward and generally avoided. You should instead use "you" to bring the action closer to the reader.

Finally, your walkthrough benefits from steps to make it easier to follow:

https://gist.github.com/moxiegirl/190be92c1aac21835b01

--->
page_title: Extending services in Compose
page_description: How to use Docker Compose's "extends" keyword to share configuration between files and projects
page_keywords: fig, composition, compose, docker, orchestration, documentation, docs

Extending services in Compose

Docker Compose's extends keyword enables sharing of common configurations
among different files, or even different projects entirely. Extending services
is useful if you have several applications that reuse commonly-defined services.
Using extends you can define a service in one place and refer to it from
anywhere.

Alternatively, you can deploy the same application to multiple environments with
a slightly different set of services in each case (or with changes to the
configuration of some services). Moreover, you can do so without copy-pasting
the configuration around.

Understand the extends configuration

When defining any service in docker-compose.yml, you can declare that you are
extending another service like this:

web:
extends:
file: common-services.ymlservice: webapp

This instructs Compose to re-use the configuration for the webapp service defined in the common-services.yml file. Suppose that
common-services.yml looks like this:

webapp:
build: .ports:
- "8000:8000"volumes:
- "/data"

In this case, you'll get exactly the same result as if you wrote
docker-compose.yml with that build, ports and volumes configuration
defined directly under web.

You can go further and define (or re-define) configuration locally in
docker-compose.yml:

web:
extends:
file: common-services.ymlservice: webappenvironment:
- DEBUG=1cpu_shares: 5

You can also write other services and link your web service to them:

web:
extends:
file: common-services.ymlservice: webappenvironment:
- DEBUG=1cpu_shares: 5links:
- dbdb:
image: postgres

For full details on how to use extends, refer to the reference.

Example use case

In this example, you repurpose the example app from the quick start
guide
. (If you're not familiar with Compose, it's recommended that
you go through the quick start first.) This example assumes you want to use
Compose both to develop an application locally and then deploy it to a
production environment.

The local and production environments are similar, but there are some
differences. In development, you mount the application code as a volume so that
it can pick up changes; in production, the code should be immutable from the
outside. This ensures it’s not accidentally changed. The development environment
uses a local Redis container, but in production another team manages the Redis
service which is listening at redis-production.example.com.

To configure with extends for this sample, you must:

  1. Define the web application as a Docker image and Compose service.

  2. Define the development environment in another Compose file.

    • Use the extends to pull in the web service
    • Configure a volume to enable code reloading.
    • Create an additional Redis service for the application to use locally.
  3. Define the production environment in a third Compose file.

    In this file, you also use extends to pull in the web service and configure
    it to talk to the external, production Redis service.

Define the web app

Defining the web application requires the following:

  1. Create an app.py file.

    This files contains a simple Python application that uses Flask to serve HTTP
    and increments a counter in Redis:

    ```python
    from flask import Flask
    from redis import Redis
    import os
    app = Flask(__name__)
    redis = Redis(host=os.environ['REDIS_HOST'], port=6379)
    @app.route('/')
    def hello():
    redis.incr('hits')
    return 'Hello World! I have been seen %s times.' % redis.get('hits')
    if __name__ == "__main__":
    app.run(host="0.0.0.0", debug=True)
    ```
    

    This code uses a REDIS_HOST environment variable to determine where to find
    Redis.

  2. Define the Python dependencies a requirements.txt file.

    flask
    redis
    
  3. Create a Dockerfile to build an image containing the app:

    FROM python:2.7 ADD . /code WORKDIR /code RUN pip install -r
    requirements.txt CMD python app.py
    
  4. Create a Compose configuration file called common.yml file.

    This configuration defines how to run the app.

    web:
    build: .
    ports:
    - "5000:5000"
    

    Typically, you would have dropped this configuration into a
    docker-compose.yml file, but to use with extends it needs to be in its own
    file.

  5. Save a close all the new files.

Define the development environment

Your define your development environment in a docker-compose.yml file:

  1. Edit the file and add an extends section.

    This section pulls in the web service from the common.yml file you created
    in the previous section.

    web:
    extends:
    file: common.yml
    service: web
    volumes:
    - .:/code
    links:
    - redis
    environment:
    - REDIS_HOST=redis
    redis:
    image: redis
    

    The new addition defines a web service that:

    • Fetches the base configuration for web out of common.yml
    • Adds volumes and links configuration to the base (common.yml)
      configuration.
    • Sets the REDIS_HOST environment variable to point to the linked redis
      container. This environment uses a stock redis image from the Docker Hub.
  2. Run docker-compose up.

    Compose creates, links, and starts a web and redis container linked together.
    It mounts your application code inside the web container.

  3. Verify that the code is mounted by changing the message in
    app.py—say, from Hello world! to Hello from Compose!.

    Don't forget to refresh your browser to see your change!

Define the production environment

You are almost done. Now, define your production environment:

  1. Create a production.yml file.

    web:
    extends:
    file: common.yml
    service: web
    environment:
    - REDIS_HOST=redis-production.example.com
    
  2. Run docker-compose -f production.yml up.

    Compose creates just a web container and configures the Redis connection via
    the REDIS_HOST environment variable. This variable points to the production
    Redis instance.

    Note: If you try to load up the webapp in your browser you'll get an
    error—redis-production.example.com isn't actually a Redis server.

You've now done a basic extends configuration. As your application develops,
you can make any necessary changes to the web service in common.yml. Compose
picks up both the development and production environments when you next run
docker-compose. You don't have to do any copy-and-paste, and you don't have to
manually keep both environments in sync.

Reference

You can use extends on any service together with other configuration keys. It
always expects a dictionary that should always contain two keys: file and
service.

The file key specifies which file to look in. It can be an absolute path or a
relative one—if relative, it's treated as relative to the current file.

The service key specifies the name of the service to extend, for example web or database.

You can extend a service that itself extends another. You can extend indefinitely. Compose does not support circular references and docker-compose returns an error if it encounters them.

Adding and overriding configuration

Compose copies configurations from the original service over to the local one,
except for links and volumes_from. These exceptions exist to avoid
implicit dependencies—you always define links and volumes_from
locally. This ensures dependencies between services are clearly visible when
reading the current file. Defining these locally also ensures changes to the
referenced file don't result in breakage.

If a configuration option is defined in both the original service and the local
service, the local value either _override_s or _extend_s the definition of the
original service. This works differently for other configuration options.

For single-value options like image, command or mem_limit, the new value
replaces the old value. This is the default behaviour - all exceptions are
listed below.
In the case of build and image, using one causes Compose to
discard the other.

# original servicebuild: .# local serviceimage: redis# resultimage: redis
# original serviceimage: redis# local servicebuild: .# resultbuild: .

For the multi-value optionsports, expose, external_links, dns and
dns_search, Compose concatenates both sets of values:

# original serviceexpose:
- "3000"# local serviceexpose:
- "4000"
- "5000"# resultexpose:
- "3000"
- "4000"
- "5000"

In the case of environment, Compose "merges" entries together with
locally-defined values taking precedence:

# original serviceenvironment:
- FOO=original
- BAR=original# local serviceenvironment:
- BAR=local
- BAZ=local# resultenvironment:
- FOO=original
- BAR=local
- BAZ=local

Finally, for volumes, Compose "merges" entries together with locally-defined
bindings taking precedence:

# original servicevolumes:
- /original-dir/foo:/foo
- /original-dir/bar:/bar# local servicevolumes:
- /local-dir/bar:/bar
- /local-dir/baz/:baz# resultvolumes:
- /original-dir/foo:/foo
- /local-dir/bar:/bar
- /local-dir/baz/:baz

Signed-off-by: Aanand Prasad <aanand.prasad@gmail.com>
@aanand

Copy link
Copy Markdown
Author

@moxiegirl Thanks! I've incorporated your changes.

@bfirsh

Copy link
Copy Markdown

LGTM

bfirsh added a commit that referenced this pull request Apr 8, 2015
Add tutorial and reference for `extends`
@bfirsh
bfirsh merged commit a1cd00e into docker:masterApr 8, 2015
yuval-k pushed a commit to yuval-k/compose that referenced this pull request Apr 10, 2015
Add tutorial and reference for `extends`
Signed-off-by: Yuval Kohavi <yuval.kohavi@gmail.com>
yuval-k pushed a commit to yuval-k/compose that referenced this pull request Apr 10, 2015
Add tutorial and reference for `extends`
Signed-off-by: Yuval Kohavi <yuval.kohavi@gmail.com>
infraAnchor pushed a commit to infraAnchor/compose that referenced this pull request Mar 6, 2026
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.24.0 to 0.25.0.
- [Commits](golang/net@v0.24.0...v0.25.0)
---
updated-dependencies:
- dependency-name: golang.org/x/net
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Write how-to guides on how to use "extends"

3 participants

@aanand@bfirsh@moxiegirl
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Add tutorial and reference for extends - #1251

Merged
bfirsh merged 1 commit into
docker:masterfrom
aanand:extends-guide
Apr 8, 2015
Merged

Add tutorial and reference for extends#1251
bfirsh merged 1 commit into
docker:masterfrom
aanand:extends-guide

Conversation

@aanand

Copy link
Copy Markdown

Closes#1111 and #1127.

@aanandaanand added this to the 1.2.0 milestone Apr 3, 2015
@bfirsh

Copy link
Copy Markdown

Nice. LGTM

cc @moxiegirl

Comment threaddocs/extends.md

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, there are some awkward constructions in here. Generally, readers use technical documents to perform tasks or gather information. For readers, these activities take place in the present. Therefore, the present tense is appropriate in most cases.

Also the first person plural "We" is awkward and generally avoided. You should instead use "you" to bring the action closer to the reader.

Finally, your walkthrough benefits from steps to make it easier to follow:

https://gist.github.com/moxiegirl/190be92c1aac21835b01

--->
page_title: Extending services in Compose
page_description: How to use Docker Compose's "extends" keyword to share configuration between files and projects
page_keywords: fig, composition, compose, docker, orchestration, documentation, docs

Extending services in Compose

Docker Compose's extends keyword enables sharing of common configurations
among different files, or even different projects entirely. Extending services
is useful if you have several applications that reuse commonly-defined services.
Using extends you can define a service in one place and refer to it from
anywhere.

Alternatively, you can deploy the same application to multiple environments with
a slightly different set of services in each case (or with changes to the
configuration of some services). Moreover, you can do so without copy-pasting
the configuration around.

Understand the extends configuration

When defining any service in docker-compose.yml, you can declare that you are
extending another service like this:

web:
extends:
file: common-services.ymlservice: webapp

This instructs Compose to re-use the configuration for the webapp service defined in the common-services.yml file. Suppose that
common-services.yml looks like this:

webapp:
build: .ports:
- "8000:8000"volumes:
- "/data"

In this case, you'll get exactly the same result as if you wrote
docker-compose.yml with that build, ports and volumes configuration
defined directly under web.

You can go further and define (or re-define) configuration locally in
docker-compose.yml:

web:
extends:
file: common-services.ymlservice: webappenvironment:
- DEBUG=1cpu_shares: 5

You can also write other services and link your web service to them:

web:
extends:
file: common-services.ymlservice: webappenvironment:
- DEBUG=1cpu_shares: 5links:
- dbdb:
image: postgres

For full details on how to use extends, refer to the reference.

Example use case

In this example, you repurpose the example app from the quick start
guide
. (If you're not familiar with Compose, it's recommended that
you go through the quick start first.) This example assumes you want to use
Compose both to develop an application locally and then deploy it to a
production environment.

The local and production environments are similar, but there are some
differences. In development, you mount the application code as a volume so that
it can pick up changes; in production, the code should be immutable from the
outside. This ensures it’s not accidentally changed. The development environment
uses a local Redis container, but in production another team manages the Redis
service which is listening at redis-production.example.com.

To configure with extends for this sample, you must:

  1. Define the web application as a Docker image and Compose service.

  2. Define the development environment in another Compose file.

    • Use the extends to pull in the web service
    • Configure a volume to enable code reloading.
    • Create an additional Redis service for the application to use locally.
  3. Define the production environment in a third Compose file.

    In this file, you also use extends to pull in the web service and configure
    it to talk to the external, production Redis service.

Define the web app

Defining the web application requires the following:

  1. Create an app.py file.

    This files contains a simple Python application that uses Flask to serve HTTP
    and increments a counter in Redis:

    ```python
    from flask import Flask
    from redis import Redis
    import os
    app = Flask(__name__)
    redis = Redis(host=os.environ['REDIS_HOST'], port=6379)
    @app.route('/')
    def hello():
    redis.incr('hits')
    return 'Hello World! I have been seen %s times.' % redis.get('hits')
    if __name__ == "__main__":
    app.run(host="0.0.0.0", debug=True)
    ```
    

    This code uses a REDIS_HOST environment variable to determine where to find
    Redis.

  2. Define the Python dependencies a requirements.txt file.

    flask
    redis
    
  3. Create a Dockerfile to build an image containing the app:

    FROM python:2.7 ADD . /code WORKDIR /code RUN pip install -r
    requirements.txt CMD python app.py
    
  4. Create a Compose configuration file called common.yml file.

    This configuration defines how to run the app.

    web:
    build: .
    ports:
    - "5000:5000"
    

    Typically, you would have dropped this configuration into a
    docker-compose.yml file, but to use with extends it needs to be in its own
    file.

  5. Save a close all the new files.

Define the development environment

Your define your development environment in a docker-compose.yml file:

  1. Edit the file and add an extends section.

    This section pulls in the web service from the common.yml file you created
    in the previous section.

    web:
    extends:
    file: common.yml
    service: web
    volumes:
    - .:/code
    links:
    - redis
    environment:
    - REDIS_HOST=redis
    redis:
    image: redis
    

    The new addition defines a web service that:

    • Fetches the base configuration for web out of common.yml
    • Adds volumes and links configuration to the base (common.yml)
      configuration.
    • Sets the REDIS_HOST environment variable to point to the linked redis
      container. This environment uses a stock redis image from the Docker Hub.
  2. Run docker-compose up.

    Compose creates, links, and starts a web and redis container linked together.
    It mounts your application code inside the web container.

  3. Verify that the code is mounted by changing the message in
    app.py—say, from Hello world! to Hello from Compose!.

    Don't forget to refresh your browser to see your change!

Define the production environment

You are almost done. Now, define your production environment:

  1. Create a production.yml file.

    web:
    extends:
    file: common.yml
    service: web
    environment:
    - REDIS_HOST=redis-production.example.com
    
  2. Run docker-compose -f production.yml up.

    Compose creates just a web container and configures the Redis connection via
    the REDIS_HOST environment variable. This variable points to the production
    Redis instance.

    Note: If you try to load up the webapp in your browser you'll get an
    error—redis-production.example.com isn't actually a Redis server.

You've now done a basic extends configuration. As your application develops,
you can make any necessary changes to the web service in common.yml. Compose
picks up both the development and production environments when you next run
docker-compose. You don't have to do any copy-and-paste, and you don't have to
manually keep both environments in sync.

Reference

You can use extends on any service together with other configuration keys. It
always expects a dictionary that should always contain two keys: file and
service.

The file key specifies which file to look in. It can be an absolute path or a
relative one—if relative, it's treated as relative to the current file.

The service key specifies the name of the service to extend, for example web or database.

You can extend a service that itself extends another. You can extend indefinitely. Compose does not support circular references and docker-compose returns an error if it encounters them.

Adding and overriding configuration

Compose copies configurations from the original service over to the local one,
except for links and volumes_from. These exceptions exist to avoid
implicit dependencies—you always define links and volumes_from
locally. This ensures dependencies between services are clearly visible when
reading the current file. Defining these locally also ensures changes to the
referenced file don't result in breakage.

If a configuration option is defined in both the original service and the local
service, the local value either _override_s or _extend_s the definition of the
original service. This works differently for other configuration options.

For single-value options like image, command or mem_limit, the new value
replaces the old value. This is the default behaviour - all exceptions are
listed below.
In the case of build and image, using one causes Compose to
discard the other.

# original servicebuild: .# local serviceimage: redis# resultimage: redis
# original serviceimage: redis# local servicebuild: .# resultbuild: .

For the multi-value optionsports, expose, external_links, dns and
dns_search, Compose concatenates both sets of values:

# original serviceexpose:
- "3000"# local serviceexpose:
- "4000"
- "5000"# resultexpose:
- "3000"
- "4000"
- "5000"

In the case of environment, Compose "merges" entries together with
locally-defined values taking precedence:

# original serviceenvironment:
- FOO=original
- BAR=original# local serviceenvironment:
- BAR=local
- BAZ=local# resultenvironment:
- FOO=original
- BAR=local
- BAZ=local

Finally, for volumes, Compose "merges" entries together with locally-defined
bindings taking precedence:

# original servicevolumes:
- /original-dir/foo:/foo
- /original-dir/bar:/bar# local servicevolumes:
- /local-dir/bar:/bar
- /local-dir/baz/:baz# resultvolumes:
- /original-dir/foo:/foo
- /local-dir/bar:/bar
- /local-dir/baz/:baz

Signed-off-by: Aanand Prasad <aanand.prasad@gmail.com>
@aanand

Copy link
Copy Markdown
Author

@moxiegirl Thanks! I've incorporated your changes.

@bfirsh

Copy link
Copy Markdown

LGTM

bfirsh added a commit that referenced this pull request Apr 8, 2015
Add tutorial and reference for `extends`
@bfirsh
bfirsh merged commit a1cd00e into docker:masterApr 8, 2015
yuval-k pushed a commit to yuval-k/compose that referenced this pull request Apr 10, 2015
Add tutorial and reference for `extends`
Signed-off-by: Yuval Kohavi <yuval.kohavi@gmail.com>
yuval-k pushed a commit to yuval-k/compose that referenced this pull request Apr 10, 2015
Add tutorial and reference for `extends`
Signed-off-by: Yuval Kohavi <yuval.kohavi@gmail.com>
infraAnchor pushed a commit to infraAnchor/compose that referenced this pull request Mar 6, 2026
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.24.0 to 0.25.0.
- [Commits](golang/net@v0.24.0...v0.25.0)
---
updated-dependencies:
- dependency-name: golang.org/x/net
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Write how-to guides on how to use "extends"

3 participants

@aanand@bfirsh@moxiegirl
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add tutorial and reference for extends - #1251

Merged
bfirsh merged 1 commit into
docker:masterfrom
aanand:extends-guide
Apr 8, 2015
Merged

Add tutorial and reference for extends#1251
bfirsh merged 1 commit into
docker:masterfrom
aanand:extends-guide

Conversation

@aanand

Copy link
Copy Markdown

Closes#1111 and #1127.

@aanandaanand added this to the 1.2.0 milestone Apr 3, 2015
@bfirsh

Copy link
Copy Markdown

Nice. LGTM

cc @moxiegirl

Comment threaddocs/extends.md

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, there are some awkward constructions in here. Generally, readers use technical documents to perform tasks or gather information. For readers, these activities take place in the present. Therefore, the present tense is appropriate in most cases.

Also the first person plural "We" is awkward and generally avoided. You should instead use "you" to bring the action closer to the reader.

Finally, your walkthrough benefits from steps to make it easier to follow:

https://gist.github.com/moxiegirl/190be92c1aac21835b01

--->
page_title: Extending services in Compose
page_description: How to use Docker Compose's "extends" keyword to share configuration between files and projects
page_keywords: fig, composition, compose, docker, orchestration, documentation, docs

Extending services in Compose

Docker Compose's extends keyword enables sharing of common configurations
among different files, or even different projects entirely. Extending services
is useful if you have several applications that reuse commonly-defined services.
Using extends you can define a service in one place and refer to it from
anywhere.

Alternatively, you can deploy the same application to multiple environments with
a slightly different set of services in each case (or with changes to the
configuration of some services). Moreover, you can do so without copy-pasting
the configuration around.

Understand the extends configuration

When defining any service in docker-compose.yml, you can declare that you are
extending another service like this:

web:
extends:
file: common-services.ymlservice: webapp

This instructs Compose to re-use the configuration for the webapp service defined in the common-services.yml file. Suppose that
common-services.yml looks like this:

webapp:
build: .ports:
- "8000:8000"volumes:
- "/data"

In this case, you'll get exactly the same result as if you wrote
docker-compose.yml with that build, ports and volumes configuration
defined directly under web.

You can go further and define (or re-define) configuration locally in
docker-compose.yml:

web:
extends:
file: common-services.ymlservice: webappenvironment:
- DEBUG=1cpu_shares: 5

You can also write other services and link your web service to them:

web:
extends:
file: common-services.ymlservice: webappenvironment:
- DEBUG=1cpu_shares: 5links:
- dbdb:
image: postgres

For full details on how to use extends, refer to the reference.

Example use case

In this example, you repurpose the example app from the quick start
guide
. (If you're not familiar with Compose, it's recommended that
you go through the quick start first.) This example assumes you want to use
Compose both to develop an application locally and then deploy it to a
production environment.

The local and production environments are similar, but there are some
differences. In development, you mount the application code as a volume so that
it can pick up changes; in production, the code should be immutable from the
outside. This ensures it’s not accidentally changed. The development environment
uses a local Redis container, but in production another team manages the Redis
service which is listening at redis-production.example.com.

To configure with extends for this sample, you must:

  1. Define the web application as a Docker image and Compose service.

  2. Define the development environment in another Compose file.

    • Use the extends to pull in the web service
    • Configure a volume to enable code reloading.
    • Create an additional Redis service for the application to use locally.
  3. Define the production environment in a third Compose file.

    In this file, you also use extends to pull in the web service and configure
    it to talk to the external, production Redis service.

Define the web app

Defining the web application requires the following:

  1. Create an app.py file.

    This files contains a simple Python application that uses Flask to serve HTTP
    and increments a counter in Redis:

    ```python
    from flask import Flask
    from redis import Redis
    import os
    app = Flask(__name__)
    redis = Redis(host=os.environ['REDIS_HOST'], port=6379)
    @app.route('/')
    def hello():
    redis.incr('hits')
    return 'Hello World! I have been seen %s times.' % redis.get('hits')
    if __name__ == "__main__":
    app.run(host="0.0.0.0", debug=True)
    ```
    

    This code uses a REDIS_HOST environment variable to determine where to find
    Redis.

  2. Define the Python dependencies a requirements.txt file.

    flask
    redis
    
  3. Create a Dockerfile to build an image containing the app:

    FROM python:2.7 ADD . /code WORKDIR /code RUN pip install -r
    requirements.txt CMD python app.py
    
  4. Create a Compose configuration file called common.yml file.

    This configuration defines how to run the app.

    web:
    build: .
    ports:
    - "5000:5000"
    

    Typically, you would have dropped this configuration into a
    docker-compose.yml file, but to use with extends it needs to be in its own
    file.

  5. Save a close all the new files.

Define the development environment

Your define your development environment in a docker-compose.yml file:

  1. Edit the file and add an extends section.

    This section pulls in the web service from the common.yml file you created
    in the previous section.

    web:
    extends:
    file: common.yml
    service: web
    volumes:
    - .:/code
    links:
    - redis
    environment:
    - REDIS_HOST=redis
    redis:
    image: redis
    

    The new addition defines a web service that:

    • Fetches the base configuration for web out of common.yml
    • Adds volumes and links configuration to the base (common.yml)
      configuration.
    • Sets the REDIS_HOST environment variable to point to the linked redis
      container. This environment uses a stock redis image from the Docker Hub.
  2. Run docker-compose up.

    Compose creates, links, and starts a web and redis container linked together.
    It mounts your application code inside the web container.

  3. Verify that the code is mounted by changing the message in
    app.py—say, from Hello world! to Hello from Compose!.

    Don't forget to refresh your browser to see your change!

Define the production environment

You are almost done. Now, define your production environment:

  1. Create a production.yml file.

    web:
    extends:
    file: common.yml
    service: web
    environment:
    - REDIS_HOST=redis-production.example.com
    
  2. Run docker-compose -f production.yml up.

    Compose creates just a web container and configures the Redis connection via
    the REDIS_HOST environment variable. This variable points to the production
    Redis instance.

    Note: If you try to load up the webapp in your browser you'll get an
    error—redis-production.example.com isn't actually a Redis server.

You've now done a basic extends configuration. As your application develops,
you can make any necessary changes to the web service in common.yml. Compose
picks up both the development and production environments when you next run
docker-compose. You don't have to do any copy-and-paste, and you don't have to
manually keep both environments in sync.

Reference

You can use extends on any service together with other configuration keys. It
always expects a dictionary that should always contain two keys: file and
service.

The file key specifies which file to look in. It can be an absolute path or a
relative one—if relative, it's treated as relative to the current file.

The service key specifies the name of the service to extend, for example web or database.

You can extend a service that itself extends another. You can extend indefinitely. Compose does not support circular references and docker-compose returns an error if it encounters them.

Adding and overriding configuration

Compose copies configurations from the original service over to the local one,
except for links and volumes_from. These exceptions exist to avoid
implicit dependencies—you always define links and volumes_from
locally. This ensures dependencies between services are clearly visible when
reading the current file. Defining these locally also ensures changes to the
referenced file don't result in breakage.

If a configuration option is defined in both the original service and the local
service, the local value either _override_s or _extend_s the definition of the
original service. This works differently for other configuration options.

For single-value options like image, command or mem_limit, the new value
replaces the old value. This is the default behaviour - all exceptions are
listed below.
In the case of build and image, using one causes Compose to
discard the other.

# original servicebuild: .# local serviceimage: redis# resultimage: redis
# original serviceimage: redis# local servicebuild: .# resultbuild: .

For the multi-value optionsports, expose, external_links, dns and
dns_search, Compose concatenates both sets of values:

# original serviceexpose:
- "3000"# local serviceexpose:
- "4000"
- "5000"# resultexpose:
- "3000"
- "4000"
- "5000"

In the case of environment, Compose "merges" entries together with
locally-defined values taking precedence:

# original serviceenvironment:
- FOO=original
- BAR=original# local serviceenvironment:
- BAR=local
- BAZ=local# resultenvironment:
- FOO=original
- BAR=local
- BAZ=local

Finally, for volumes, Compose "merges" entries together with locally-defined
bindings taking precedence:

# original servicevolumes:
- /original-dir/foo:/foo
- /original-dir/bar:/bar# local servicevolumes:
- /local-dir/bar:/bar
- /local-dir/baz/:baz# resultvolumes:
- /original-dir/foo:/foo
- /local-dir/bar:/bar
- /local-dir/baz/:baz

Signed-off-by: Aanand Prasad <aanand.prasad@gmail.com>
@aanand

Copy link
Copy Markdown
Author

@moxiegirl Thanks! I've incorporated your changes.

@bfirsh

Copy link
Copy Markdown

LGTM

bfirsh added a commit that referenced this pull request Apr 8, 2015
Add tutorial and reference for `extends`
@bfirsh
bfirsh merged commit a1cd00e into docker:masterApr 8, 2015
yuval-k pushed a commit to yuval-k/compose that referenced this pull request Apr 10, 2015
Add tutorial and reference for `extends`
Signed-off-by: Yuval Kohavi <yuval.kohavi@gmail.com>
yuval-k pushed a commit to yuval-k/compose that referenced this pull request Apr 10, 2015
Add tutorial and reference for `extends`
Signed-off-by: Yuval Kohavi <yuval.kohavi@gmail.com>
infraAnchor pushed a commit to infraAnchor/compose that referenced this pull request Mar 6, 2026
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.24.0 to 0.25.0.
- [Commits](golang/net@v0.24.0...v0.25.0)
---
updated-dependencies:
- dependency-name: golang.org/x/net
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Write how-to guides on how to use "extends"

3 participants

@aanand@bfirsh@moxiegirl
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add tutorial and reference for extends - #1251

Merged
bfirsh merged 1 commit into
docker:masterfrom
aanand:extends-guide
Apr 8, 2015
Merged

Add tutorial and reference for extends#1251
bfirsh merged 1 commit into
docker:masterfrom
aanand:extends-guide

Conversation

@aanand

Copy link
Copy Markdown

Closes#1111 and #1127.

@aanandaanand added this to the 1.2.0 milestone Apr 3, 2015
@bfirsh

Copy link
Copy Markdown

Nice. LGTM

cc @moxiegirl

Comment threaddocs/extends.md

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, there are some awkward constructions in here. Generally, readers use technical documents to perform tasks or gather information. For readers, these activities take place in the present. Therefore, the present tense is appropriate in most cases.

Also the first person plural "We" is awkward and generally avoided. You should instead use "you" to bring the action closer to the reader.

Finally, your walkthrough benefits from steps to make it easier to follow:

https://gist.github.com/moxiegirl/190be92c1aac21835b01

--->
page_title: Extending services in Compose
page_description: How to use Docker Compose's "extends" keyword to share configuration between files and projects
page_keywords: fig, composition, compose, docker, orchestration, documentation, docs

Extending services in Compose

Docker Compose's extends keyword enables sharing of common configurations
among different files, or even different projects entirely. Extending services
is useful if you have several applications that reuse commonly-defined services.
Using extends you can define a service in one place and refer to it from
anywhere.

Alternatively, you can deploy the same application to multiple environments with
a slightly different set of services in each case (or with changes to the
configuration of some services). Moreover, you can do so without copy-pasting
the configuration around.

Understand the extends configuration

When defining any service in docker-compose.yml, you can declare that you are
extending another service like this:

web:
extends:
file: common-services.ymlservice: webapp

This instructs Compose to re-use the configuration for the webapp service defined in the common-services.yml file. Suppose that
common-services.yml looks like this:

webapp:
build: .ports:
- "8000:8000"volumes:
- "/data"

In this case, you'll get exactly the same result as if you wrote
docker-compose.yml with that build, ports and volumes configuration
defined directly under web.

You can go further and define (or re-define) configuration locally in
docker-compose.yml:

web:
extends:
file: common-services.ymlservice: webappenvironment:
- DEBUG=1cpu_shares: 5

You can also write other services and link your web service to them:

web:
extends:
file: common-services.ymlservice: webappenvironment:
- DEBUG=1cpu_shares: 5links:
- dbdb:
image: postgres

For full details on how to use extends, refer to the reference.

Example use case

In this example, you repurpose the example app from the quick start
guide
. (If you're not familiar with Compose, it's recommended that
you go through the quick start first.) This example assumes you want to use
Compose both to develop an application locally and then deploy it to a
production environment.

The local and production environments are similar, but there are some
differences. In development, you mount the application code as a volume so that
it can pick up changes; in production, the code should be immutable from the
outside. This ensures it’s not accidentally changed. The development environment
uses a local Redis container, but in production another team manages the Redis
service which is listening at redis-production.example.com.

To configure with extends for this sample, you must:

  1. Define the web application as a Docker image and Compose service.

  2. Define the development environment in another Compose file.

    • Use the extends to pull in the web service
    • Configure a volume to enable code reloading.
    • Create an additional Redis service for the application to use locally.
  3. Define the production environment in a third Compose file.

    In this file, you also use extends to pull in the web service and configure
    it to talk to the external, production Redis service.

Define the web app

Defining the web application requires the following:

  1. Create an app.py file.

    This files contains a simple Python application that uses Flask to serve HTTP
    and increments a counter in Redis:

    ```python
    from flask import Flask
    from redis import Redis
    import os
    app = Flask(__name__)
    redis = Redis(host=os.environ['REDIS_HOST'], port=6379)
    @app.route('/')
    def hello():
    redis.incr('hits')
    return 'Hello World! I have been seen %s times.' % redis.get('hits')
    if __name__ == "__main__":
    app.run(host="0.0.0.0", debug=True)
    ```
    

    This code uses a REDIS_HOST environment variable to determine where to find
    Redis.

  2. Define the Python dependencies a requirements.txt file.

    flask
    redis
    
  3. Create a Dockerfile to build an image containing the app:

    FROM python:2.7 ADD . /code WORKDIR /code RUN pip install -r
    requirements.txt CMD python app.py
    
  4. Create a Compose configuration file called common.yml file.

    This configuration defines how to run the app.

    web:
    build: .
    ports:
    - "5000:5000"
    

    Typically, you would have dropped this configuration into a
    docker-compose.yml file, but to use with extends it needs to be in its own
    file.

  5. Save a close all the new files.

Define the development environment

Your define your development environment in a docker-compose.yml file:

  1. Edit the file and add an extends section.

    This section pulls in the web service from the common.yml file you created
    in the previous section.

    web:
    extends:
    file: common.yml
    service: web
    volumes:
    - .:/code
    links:
    - redis
    environment:
    - REDIS_HOST=redis
    redis:
    image: redis
    

    The new addition defines a web service that:

    • Fetches the base configuration for web out of common.yml
    • Adds volumes and links configuration to the base (common.yml)
      configuration.
    • Sets the REDIS_HOST environment variable to point to the linked redis
      container. This environment uses a stock redis image from the Docker Hub.
  2. Run docker-compose up.

    Compose creates, links, and starts a web and redis container linked together.
    It mounts your application code inside the web container.

  3. Verify that the code is mounted by changing the message in
    app.py—say, from Hello world! to Hello from Compose!.

    Don't forget to refresh your browser to see your change!

Define the production environment

You are almost done. Now, define your production environment:

  1. Create a production.yml file.

    web:
    extends:
    file: common.yml
    service: web
    environment:
    - REDIS_HOST=redis-production.example.com
    
  2. Run docker-compose -f production.yml up.

    Compose creates just a web container and configures the Redis connection via
    the REDIS_HOST environment variable. This variable points to the production
    Redis instance.

    Note: If you try to load up the webapp in your browser you'll get an
    error—redis-production.example.com isn't actually a Redis server.

You've now done a basic extends configuration. As your application develops,
you can make any necessary changes to the web service in common.yml. Compose
picks up both the development and production environments when you next run
docker-compose. You don't have to do any copy-and-paste, and you don't have to
manually keep both environments in sync.

Reference

You can use extends on any service together with other configuration keys. It
always expects a dictionary that should always contain two keys: file and
service.

The file key specifies which file to look in. It can be an absolute path or a
relative one—if relative, it's treated as relative to the current file.

The service key specifies the name of the service to extend, for example web or database.

You can extend a service that itself extends another. You can extend indefinitely. Compose does not support circular references and docker-compose returns an error if it encounters them.

Adding and overriding configuration

Compose copies configurations from the original service over to the local one,
except for links and volumes_from. These exceptions exist to avoid
implicit dependencies—you always define links and volumes_from
locally. This ensures dependencies between services are clearly visible when
reading the current file. Defining these locally also ensures changes to the
referenced file don't result in breakage.

If a configuration option is defined in both the original service and the local
service, the local value either _override_s or _extend_s the definition of the
original service. This works differently for other configuration options.

For single-value options like image, command or mem_limit, the new value
replaces the old value. This is the default behaviour - all exceptions are
listed below.
In the case of build and image, using one causes Compose to
discard the other.

# original servicebuild: .# local serviceimage: redis# resultimage: redis
# original serviceimage: redis# local servicebuild: .# resultbuild: .

For the multi-value optionsports, expose, external_links, dns and
dns_search, Compose concatenates both sets of values:

# original serviceexpose:
- "3000"# local serviceexpose:
- "4000"
- "5000"# resultexpose:
- "3000"
- "4000"
- "5000"

In the case of environment, Compose "merges" entries together with
locally-defined values taking precedence:

# original serviceenvironment:
- FOO=original
- BAR=original# local serviceenvironment:
- BAR=local
- BAZ=local# resultenvironment:
- FOO=original
- BAR=local
- BAZ=local

Finally, for volumes, Compose "merges" entries together with locally-defined
bindings taking precedence:

# original servicevolumes:
- /original-dir/foo:/foo
- /original-dir/bar:/bar# local servicevolumes:
- /local-dir/bar:/bar
- /local-dir/baz/:baz# resultvolumes:
- /original-dir/foo:/foo
- /local-dir/bar:/bar
- /local-dir/baz/:baz

Signed-off-by: Aanand Prasad <aanand.prasad@gmail.com>
@aanand

Copy link
Copy Markdown
Author

@moxiegirl Thanks! I've incorporated your changes.

@bfirsh

Copy link
Copy Markdown

LGTM

bfirsh added a commit that referenced this pull request Apr 8, 2015
Add tutorial and reference for `extends`
@bfirsh
bfirsh merged commit a1cd00e into docker:masterApr 8, 2015
yuval-k pushed a commit to yuval-k/compose that referenced this pull request Apr 10, 2015
Add tutorial and reference for `extends`
Signed-off-by: Yuval Kohavi <yuval.kohavi@gmail.com>
yuval-k pushed a commit to yuval-k/compose that referenced this pull request Apr 10, 2015
Add tutorial and reference for `extends`
Signed-off-by: Yuval Kohavi <yuval.kohavi@gmail.com>
infraAnchor pushed a commit to infraAnchor/compose that referenced this pull request Mar 6, 2026
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.24.0 to 0.25.0.
- [Commits](golang/net@v0.24.0...v0.25.0)
---
updated-dependencies:
- dependency-name: golang.org/x/net
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Write how-to guides on how to use "extends"

3 participants

@aanand@bfirsh@moxiegirl
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Add tutorial and reference for extends - #1251

Merged
bfirsh merged 1 commit into
docker:masterfrom
aanand:extends-guide
Apr 8, 2015
Merged

Add tutorial and reference for extends#1251
bfirsh merged 1 commit into
docker:masterfrom
aanand:extends-guide

Conversation

@aanand

Copy link
Copy Markdown

Closes#1111 and #1127.

@aanandaanand added this to the 1.2.0 milestone Apr 3, 2015
@bfirsh

Copy link
Copy Markdown

Nice. LGTM

cc @moxiegirl

Comment threaddocs/extends.md

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, there are some awkward constructions in here. Generally, readers use technical documents to perform tasks or gather information. For readers, these activities take place in the present. Therefore, the present tense is appropriate in most cases.

Also the first person plural "We" is awkward and generally avoided. You should instead use "you" to bring the action closer to the reader.

Finally, your walkthrough benefits from steps to make it easier to follow:

https://gist.github.com/moxiegirl/190be92c1aac21835b01

--->
page_title: Extending services in Compose
page_description: How to use Docker Compose's "extends" keyword to share configuration between files and projects
page_keywords: fig, composition, compose, docker, orchestration, documentation, docs

Extending services in Compose

Docker Compose's extends keyword enables sharing of common configurations
among different files, or even different projects entirely. Extending services
is useful if you have several applications that reuse commonly-defined services.
Using extends you can define a service in one place and refer to it from
anywhere.

Alternatively, you can deploy the same application to multiple environments with
a slightly different set of services in each case (or with changes to the
configuration of some services). Moreover, you can do so without copy-pasting
the configuration around.

Understand the extends configuration

When defining any service in docker-compose.yml, you can declare that you are
extending another service like this:

web:
extends:
file: common-services.ymlservice: webapp

This instructs Compose to re-use the configuration for the webapp service defined in the common-services.yml file. Suppose that
common-services.yml looks like this:

webapp:
build: .ports:
- "8000:8000"volumes:
- "/data"

In this case, you'll get exactly the same result as if you wrote
docker-compose.yml with that build, ports and volumes configuration
defined directly under web.

You can go further and define (or re-define) configuration locally in
docker-compose.yml:

web:
extends:
file: common-services.ymlservice: webappenvironment:
- DEBUG=1cpu_shares: 5

You can also write other services and link your web service to them:

web:
extends:
file: common-services.ymlservice: webappenvironment:
- DEBUG=1cpu_shares: 5links:
- dbdb:
image: postgres

For full details on how to use extends, refer to the reference.

Example use case

In this example, you repurpose the example app from the quick start
guide
. (If you're not familiar with Compose, it's recommended that
you go through the quick start first.) This example assumes you want to use
Compose both to develop an application locally and then deploy it to a
production environment.

The local and production environments are similar, but there are some
differences. In development, you mount the application code as a volume so that
it can pick up changes; in production, the code should be immutable from the
outside. This ensures it’s not accidentally changed. The development environment
uses a local Redis container, but in production another team manages the Redis
service which is listening at redis-production.example.com.

To configure with extends for this sample, you must:

  1. Define the web application as a Docker image and Compose service.

  2. Define the development environment in another Compose file.

    • Use the extends to pull in the web service
    • Configure a volume to enable code reloading.
    • Create an additional Redis service for the application to use locally.
  3. Define the production environment in a third Compose file.

    In this file, you also use extends to pull in the web service and configure
    it to talk to the external, production Redis service.

Define the web app

Defining the web application requires the following:

  1. Create an app.py file.

    This files contains a simple Python application that uses Flask to serve HTTP
    and increments a counter in Redis:

    ```python
    from flask import Flask
    from redis import Redis
    import os
    app = Flask(__name__)
    redis = Redis(host=os.environ['REDIS_HOST'], port=6379)
    @app.route('/')
    def hello():
    redis.incr('hits')
    return 'Hello World! I have been seen %s times.' % redis.get('hits')
    if __name__ == "__main__":
    app.run(host="0.0.0.0", debug=True)
    ```
    

    This code uses a REDIS_HOST environment variable to determine where to find
    Redis.

  2. Define the Python dependencies a requirements.txt file.

    flask
    redis
    
  3. Create a Dockerfile to build an image containing the app:

    FROM python:2.7 ADD . /code WORKDIR /code RUN pip install -r
    requirements.txt CMD python app.py
    
  4. Create a Compose configuration file called common.yml file.

    This configuration defines how to run the app.

    web:
    build: .
    ports:
    - "5000:5000"
    

    Typically, you would have dropped this configuration into a
    docker-compose.yml file, but to use with extends it needs to be in its own
    file.

  5. Save a close all the new files.

Define the development environment

Your define your development environment in a docker-compose.yml file:

  1. Edit the file and add an extends section.

    This section pulls in the web service from the common.yml file you created
    in the previous section.

    web:
    extends:
    file: common.yml
    service: web
    volumes:
    - .:/code
    links:
    - redis
    environment:
    - REDIS_HOST=redis
    redis:
    image: redis
    

    The new addition defines a web service that:

    • Fetches the base configuration for web out of common.yml
    • Adds volumes and links configuration to the base (common.yml)
      configuration.
    • Sets the REDIS_HOST environment variable to point to the linked redis
      container. This environment uses a stock redis image from the Docker Hub.
  2. Run docker-compose up.

    Compose creates, links, and starts a web and redis container linked together.
    It mounts your application code inside the web container.

  3. Verify that the code is mounted by changing the message in
    app.py—say, from Hello world! to Hello from Compose!.

    Don't forget to refresh your browser to see your change!

Define the production environment

You are almost done. Now, define your production environment:

  1. Create a production.yml file.

    web:
    extends:
    file: common.yml
    service: web
    environment:
    - REDIS_HOST=redis-production.example.com
    
  2. Run docker-compose -f production.yml up.

    Compose creates just a web container and configures the Redis connection via
    the REDIS_HOST environment variable. This variable points to the production
    Redis instance.

    Note: If you try to load up the webapp in your browser you'll get an
    error—redis-production.example.com isn't actually a Redis server.

You've now done a basic extends configuration. As your application develops,
you can make any necessary changes to the web service in common.yml. Compose
picks up both the development and production environments when you next run
docker-compose. You don't have to do any copy-and-paste, and you don't have to
manually keep both environments in sync.

Reference

You can use extends on any service together with other configuration keys. It
always expects a dictionary that should always contain two keys: file and
service.

The file key specifies which file to look in. It can be an absolute path or a
relative one—if relative, it's treated as relative to the current file.

The service key specifies the name of the service to extend, for example web or database.

You can extend a service that itself extends another. You can extend indefinitely. Compose does not support circular references and docker-compose returns an error if it encounters them.

Adding and overriding configuration

Compose copies configurations from the original service over to the local one,
except for links and volumes_from. These exceptions exist to avoid
implicit dependencies—you always define links and volumes_from
locally. This ensures dependencies between services are clearly visible when
reading the current file. Defining these locally also ensures changes to the
referenced file don't result in breakage.

If a configuration option is defined in both the original service and the local
service, the local value either _override_s or _extend_s the definition of the
original service. This works differently for other configuration options.

For single-value options like image, command or mem_limit, the new value
replaces the old value. This is the default behaviour - all exceptions are
listed below.
In the case of build and image, using one causes Compose to
discard the other.

# original servicebuild: .# local serviceimage: redis# resultimage: redis
# original serviceimage: redis# local servicebuild: .# resultbuild: .

For the multi-value optionsports, expose, external_links, dns and
dns_search, Compose concatenates both sets of values:

# original serviceexpose:
- "3000"# local serviceexpose:
- "4000"
- "5000"# resultexpose:
- "3000"
- "4000"
- "5000"

In the case of environment, Compose "merges" entries together with
locally-defined values taking precedence:

# original serviceenvironment:
- FOO=original
- BAR=original# local serviceenvironment:
- BAR=local
- BAZ=local# resultenvironment:
- FOO=original
- BAR=local
- BAZ=local

Finally, for volumes, Compose "merges" entries together with locally-defined
bindings taking precedence:

# original servicevolumes:
- /original-dir/foo:/foo
- /original-dir/bar:/bar# local servicevolumes:
- /local-dir/bar:/bar
- /local-dir/baz/:baz# resultvolumes:
- /original-dir/foo:/foo
- /local-dir/bar:/bar
- /local-dir/baz/:baz

Signed-off-by: Aanand Prasad <aanand.prasad@gmail.com>
@aanand

Copy link
Copy Markdown
Author

@moxiegirl Thanks! I've incorporated your changes.

@bfirsh

Copy link
Copy Markdown

LGTM

bfirsh added a commit that referenced this pull request Apr 8, 2015
Add tutorial and reference for `extends`
@bfirsh
bfirsh merged commit a1cd00e into docker:masterApr 8, 2015
yuval-k pushed a commit to yuval-k/compose that referenced this pull request Apr 10, 2015
Add tutorial and reference for `extends`
Signed-off-by: Yuval Kohavi <yuval.kohavi@gmail.com>
yuval-k pushed a commit to yuval-k/compose that referenced this pull request Apr 10, 2015
Add tutorial and reference for `extends`
Signed-off-by: Yuval Kohavi <yuval.kohavi@gmail.com>
infraAnchor pushed a commit to infraAnchor/compose that referenced this pull request Mar 6, 2026
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.24.0 to 0.25.0.
- [Commits](golang/net@v0.24.0...v0.25.0)
---
updated-dependencies:
- dependency-name: golang.org/x/net
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Write how-to guides on how to use "extends"

3 participants

@aanand@bfirsh@moxiegirl
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add tutorial and reference for extends - #1251

Merged
bfirsh merged 1 commit into
docker:masterfrom
aanand:extends-guide
Apr 8, 2015
Merged

Add tutorial and reference for extends#1251
bfirsh merged 1 commit into
docker:masterfrom
aanand:extends-guide

Conversation

@aanand

Copy link
Copy Markdown

Closes#1111 and #1127.

@aanandaanand added this to the 1.2.0 milestone Apr 3, 2015
@bfirsh

Copy link
Copy Markdown

Nice. LGTM

cc @moxiegirl

Comment threaddocs/extends.md

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, there are some awkward constructions in here. Generally, readers use technical documents to perform tasks or gather information. For readers, these activities take place in the present. Therefore, the present tense is appropriate in most cases.

Also the first person plural "We" is awkward and generally avoided. You should instead use "you" to bring the action closer to the reader.

Finally, your walkthrough benefits from steps to make it easier to follow:

https://gist.github.com/moxiegirl/190be92c1aac21835b01

--->
page_title: Extending services in Compose
page_description: How to use Docker Compose's "extends" keyword to share configuration between files and projects
page_keywords: fig, composition, compose, docker, orchestration, documentation, docs

Extending services in Compose

Docker Compose's extends keyword enables sharing of common configurations
among different files, or even different projects entirely. Extending services
is useful if you have several applications that reuse commonly-defined services.
Using extends you can define a service in one place and refer to it from
anywhere.

Alternatively, you can deploy the same application to multiple environments with
a slightly different set of services in each case (or with changes to the
configuration of some services). Moreover, you can do so without copy-pasting
the configuration around.

Understand the extends configuration

When defining any service in docker-compose.yml, you can declare that you are
extending another service like this:

web:
extends:
file: common-services.ymlservice: webapp

This instructs Compose to re-use the configuration for the webapp service defined in the common-services.yml file. Suppose that
common-services.yml looks like this:

webapp:
build: .ports:
- "8000:8000"volumes:
- "/data"

In this case, you'll get exactly the same result as if you wrote
docker-compose.yml with that build, ports and volumes configuration
defined directly under web.

You can go further and define (or re-define) configuration locally in
docker-compose.yml:

web:
extends:
file: common-services.ymlservice: webappenvironment:
- DEBUG=1cpu_shares: 5

You can also write other services and link your web service to them:

web:
extends:
file: common-services.ymlservice: webappenvironment:
- DEBUG=1cpu_shares: 5links:
- dbdb:
image: postgres

For full details on how to use extends, refer to the reference.

Example use case

In this example, you repurpose the example app from the quick start
guide
. (If you're not familiar with Compose, it's recommended that
you go through the quick start first.) This example assumes you want to use
Compose both to develop an application locally and then deploy it to a
production environment.

The local and production environments are similar, but there are some
differences. In development, you mount the application code as a volume so that
it can pick up changes; in production, the code should be immutable from the
outside. This ensures it’s not accidentally changed. The development environment
uses a local Redis container, but in production another team manages the Redis
service which is listening at redis-production.example.com.

To configure with extends for this sample, you must:

  1. Define the web application as a Docker image and Compose service.

  2. Define the development environment in another Compose file.

    • Use the extends to pull in the web service
    • Configure a volume to enable code reloading.
    • Create an additional Redis service for the application to use locally.
  3. Define the production environment in a third Compose file.

    In this file, you also use extends to pull in the web service and configure
    it to talk to the external, production Redis service.

Define the web app

Defining the web application requires the following:

  1. Create an app.py file.

    This files contains a simple Python application that uses Flask to serve HTTP
    and increments a counter in Redis:

    ```python
    from flask import Flask
    from redis import Redis
    import os
    app = Flask(__name__)
    redis = Redis(host=os.environ['REDIS_HOST'], port=6379)
    @app.route('/')
    def hello():
    redis.incr('hits')
    return 'Hello World! I have been seen %s times.' % redis.get('hits')
    if __name__ == "__main__":
    app.run(host="0.0.0.0", debug=True)
    ```
    

    This code uses a REDIS_HOST environment variable to determine where to find
    Redis.

  2. Define the Python dependencies a requirements.txt file.

    flask
    redis
    
  3. Create a Dockerfile to build an image containing the app:

    FROM python:2.7 ADD . /code WORKDIR /code RUN pip install -r
    requirements.txt CMD python app.py
    
  4. Create a Compose configuration file called common.yml file.

    This configuration defines how to run the app.

    web:
    build: .
    ports:
    - "5000:5000"
    

    Typically, you would have dropped this configuration into a
    docker-compose.yml file, but to use with extends it needs to be in its own
    file.

  5. Save a close all the new files.

Define the development environment

Your define your development environment in a docker-compose.yml file:

  1. Edit the file and add an extends section.

    This section pulls in the web service from the common.yml file you created
    in the previous section.

    web:
    extends:
    file: common.yml
    service: web
    volumes:
    - .:/code
    links:
    - redis
    environment:
    - REDIS_HOST=redis
    redis:
    image: redis
    

    The new addition defines a web service that:

    • Fetches the base configuration for web out of common.yml
    • Adds volumes and links configuration to the base (common.yml)
      configuration.
    • Sets the REDIS_HOST environment variable to point to the linked redis
      container. This environment uses a stock redis image from the Docker Hub.
  2. Run docker-compose up.

    Compose creates, links, and starts a web and redis container linked together.
    It mounts your application code inside the web container.

  3. Verify that the code is mounted by changing the message in
    app.py—say, from Hello world! to Hello from Compose!.

    Don't forget to refresh your browser to see your change!

Define the production environment

You are almost done. Now, define your production environment:

  1. Create a production.yml file.

    web:
    extends:
    file: common.yml
    service: web
    environment:
    - REDIS_HOST=redis-production.example.com
    
  2. Run docker-compose -f production.yml up.

    Compose creates just a web container and configures the Redis connection via
    the REDIS_HOST environment variable. This variable points to the production
    Redis instance.

    Note: If you try to load up the webapp in your browser you'll get an
    error—redis-production.example.com isn't actually a Redis server.

You've now done a basic extends configuration. As your application develops,
you can make any necessary changes to the web service in common.yml. Compose
picks up both the development and production environments when you next run
docker-compose. You don't have to do any copy-and-paste, and you don't have to
manually keep both environments in sync.

Reference

You can use extends on any service together with other configuration keys. It
always expects a dictionary that should always contain two keys: file and
service.

The file key specifies which file to look in. It can be an absolute path or a
relative one—if relative, it's treated as relative to the current file.

The service key specifies the name of the service to extend, for example web or database.

You can extend a service that itself extends another. You can extend indefinitely. Compose does not support circular references and docker-compose returns an error if it encounters them.

Adding and overriding configuration

Compose copies configurations from the original service over to the local one,
except for links and volumes_from. These exceptions exist to avoid
implicit dependencies—you always define links and volumes_from
locally. This ensures dependencies between services are clearly visible when
reading the current file. Defining these locally also ensures changes to the
referenced file don't result in breakage.

If a configuration option is defined in both the original service and the local
service, the local value either _override_s or _extend_s the definition of the
original service. This works differently for other configuration options.

For single-value options like image, command or mem_limit, the new value
replaces the old value. This is the default behaviour - all exceptions are
listed below.
In the case of build and image, using one causes Compose to
discard the other.

# original servicebuild: .# local serviceimage: redis# resultimage: redis
# original serviceimage: redis# local servicebuild: .# resultbuild: .

For the multi-value optionsports, expose, external_links, dns and
dns_search, Compose concatenates both sets of values:

# original serviceexpose:
- "3000"# local serviceexpose:
- "4000"
- "5000"# resultexpose:
- "3000"
- "4000"
- "5000"

In the case of environment, Compose "merges" entries together with
locally-defined values taking precedence:

# original serviceenvironment:
- FOO=original
- BAR=original# local serviceenvironment:
- BAR=local
- BAZ=local# resultenvironment:
- FOO=original
- BAR=local
- BAZ=local

Finally, for volumes, Compose "merges" entries together with locally-defined
bindings taking precedence:

# original servicevolumes:
- /original-dir/foo:/foo
- /original-dir/bar:/bar# local servicevolumes:
- /local-dir/bar:/bar
- /local-dir/baz/:baz# resultvolumes:
- /original-dir/foo:/foo
- /local-dir/bar:/bar
- /local-dir/baz/:baz

Signed-off-by: Aanand Prasad <aanand.prasad@gmail.com>
@aanand

Copy link
Copy Markdown
Author

@moxiegirl Thanks! I've incorporated your changes.

@bfirsh

Copy link
Copy Markdown

LGTM

bfirsh added a commit that referenced this pull request Apr 8, 2015
Add tutorial and reference for `extends`
@bfirsh
bfirsh merged commit a1cd00e into docker:masterApr 8, 2015
yuval-k pushed a commit to yuval-k/compose that referenced this pull request Apr 10, 2015
Add tutorial and reference for `extends`
Signed-off-by: Yuval Kohavi <yuval.kohavi@gmail.com>
yuval-k pushed a commit to yuval-k/compose that referenced this pull request Apr 10, 2015
Add tutorial and reference for `extends`
Signed-off-by: Yuval Kohavi <yuval.kohavi@gmail.com>
infraAnchor pushed a commit to infraAnchor/compose that referenced this pull request Mar 6, 2026
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.24.0 to 0.25.0.
- [Commits](golang/net@v0.24.0...v0.25.0)
---
updated-dependencies:
- dependency-name: golang.org/x/net
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Write how-to guides on how to use "extends"

3 participants

@aanand@bfirsh@moxiegirl
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add tutorial and reference for extends - #1251

Merged
bfirsh merged 1 commit into
docker:masterfrom
aanand:extends-guide
Apr 8, 2015
Merged

Add tutorial and reference for extends#1251
bfirsh merged 1 commit into
docker:masterfrom
aanand:extends-guide

Conversation

@aanand

Copy link
Copy Markdown

Closes#1111 and #1127.

@aanandaanand added this to the 1.2.0 milestone Apr 3, 2015
@bfirsh

Copy link
Copy Markdown

Nice. LGTM

cc @moxiegirl

Comment threaddocs/extends.md

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, there are some awkward constructions in here. Generally, readers use technical documents to perform tasks or gather information. For readers, these activities take place in the present. Therefore, the present tense is appropriate in most cases.

Also the first person plural "We" is awkward and generally avoided. You should instead use "you" to bring the action closer to the reader.

Finally, your walkthrough benefits from steps to make it easier to follow:

https://gist.github.com/moxiegirl/190be92c1aac21835b01

--->
page_title: Extending services in Compose
page_description: How to use Docker Compose's "extends" keyword to share configuration between files and projects
page_keywords: fig, composition, compose, docker, orchestration, documentation, docs

Extending services in Compose

Docker Compose's extends keyword enables sharing of common configurations
among different files, or even different projects entirely. Extending services
is useful if you have several applications that reuse commonly-defined services.
Using extends you can define a service in one place and refer to it from
anywhere.

Alternatively, you can deploy the same application to multiple environments with
a slightly different set of services in each case (or with changes to the
configuration of some services). Moreover, you can do so without copy-pasting
the configuration around.

Understand the extends configuration

When defining any service in docker-compose.yml, you can declare that you are
extending another service like this:

web:
extends:
file: common-services.ymlservice: webapp

This instructs Compose to re-use the configuration for the webapp service defined in the common-services.yml file. Suppose that
common-services.yml looks like this:

webapp:
build: .ports:
- "8000:8000"volumes:
- "/data"

In this case, you'll get exactly the same result as if you wrote
docker-compose.yml with that build, ports and volumes configuration
defined directly under web.

You can go further and define (or re-define) configuration locally in
docker-compose.yml:

web:
extends:
file: common-services.ymlservice: webappenvironment:
- DEBUG=1cpu_shares: 5

You can also write other services and link your web service to them:

web:
extends:
file: common-services.ymlservice: webappenvironment:
- DEBUG=1cpu_shares: 5links:
- dbdb:
image: postgres

For full details on how to use extends, refer to the reference.

Example use case

In this example, you repurpose the example app from the quick start
guide
. (If you're not familiar with Compose, it's recommended that
you go through the quick start first.) This example assumes you want to use
Compose both to develop an application locally and then deploy it to a
production environment.

The local and production environments are similar, but there are some
differences. In development, you mount the application code as a volume so that
it can pick up changes; in production, the code should be immutable from the
outside. This ensures it’s not accidentally changed. The development environment
uses a local Redis container, but in production another team manages the Redis
service which is listening at redis-production.example.com.

To configure with extends for this sample, you must:

  1. Define the web application as a Docker image and Compose service.

  2. Define the development environment in another Compose file.

    • Use the extends to pull in the web service
    • Configure a volume to enable code reloading.
    • Create an additional Redis service for the application to use locally.
  3. Define the production environment in a third Compose file.

    In this file, you also use extends to pull in the web service and configure
    it to talk to the external, production Redis service.

Define the web app

Defining the web application requires the following:

  1. Create an app.py file.

    This files contains a simple Python application that uses Flask to serve HTTP
    and increments a counter in Redis:

    ```python
    from flask import Flask
    from redis import Redis
    import os
    app = Flask(__name__)
    redis = Redis(host=os.environ['REDIS_HOST'], port=6379)
    @app.route('/')
    def hello():
    redis.incr('hits')
    return 'Hello World! I have been seen %s times.' % redis.get('hits')
    if __name__ == "__main__":
    app.run(host="0.0.0.0", debug=True)
    ```
    

    This code uses a REDIS_HOST environment variable to determine where to find
    Redis.

  2. Define the Python dependencies a requirements.txt file.

    flask
    redis
    
  3. Create a Dockerfile to build an image containing the app:

    FROM python:2.7 ADD . /code WORKDIR /code RUN pip install -r
    requirements.txt CMD python app.py
    
  4. Create a Compose configuration file called common.yml file.

    This configuration defines how to run the app.

    web:
    build: .
    ports:
    - "5000:5000"
    

    Typically, you would have dropped this configuration into a
    docker-compose.yml file, but to use with extends it needs to be in its own
    file.

  5. Save a close all the new files.

Define the development environment

Your define your development environment in a docker-compose.yml file:

  1. Edit the file and add an extends section.

    This section pulls in the web service from the common.yml file you created
    in the previous section.

    web:
    extends:
    file: common.yml
    service: web
    volumes:
    - .:/code
    links:
    - redis
    environment:
    - REDIS_HOST=redis
    redis:
    image: redis
    

    The new addition defines a web service that:

    • Fetches the base configuration for web out of common.yml
    • Adds volumes and links configuration to the base (common.yml)
      configuration.
    • Sets the REDIS_HOST environment variable to point to the linked redis
      container. This environment uses a stock redis image from the Docker Hub.
  2. Run docker-compose up.

    Compose creates, links, and starts a web and redis container linked together.
    It mounts your application code inside the web container.

  3. Verify that the code is mounted by changing the message in
    app.py—say, from Hello world! to Hello from Compose!.

    Don't forget to refresh your browser to see your change!

Define the production environment

You are almost done. Now, define your production environment:

  1. Create a production.yml file.

    web:
    extends:
    file: common.yml
    service: web
    environment:
    - REDIS_HOST=redis-production.example.com
    
  2. Run docker-compose -f production.yml up.

    Compose creates just a web container and configures the Redis connection via
    the REDIS_HOST environment variable. This variable points to the production
    Redis instance.

    Note: If you try to load up the webapp in your browser you'll get an
    error—redis-production.example.com isn't actually a Redis server.

You've now done a basic extends configuration. As your application develops,
you can make any necessary changes to the web service in common.yml. Compose
picks up both the development and production environments when you next run
docker-compose. You don't have to do any copy-and-paste, and you don't have to
manually keep both environments in sync.

Reference

You can use extends on any service together with other configuration keys. It
always expects a dictionary that should always contain two keys: file and
service.

The file key specifies which file to look in. It can be an absolute path or a
relative one—if relative, it's treated as relative to the current file.

The service key specifies the name of the service to extend, for example web or database.

You can extend a service that itself extends another. You can extend indefinitely. Compose does not support circular references and docker-compose returns an error if it encounters them.

Adding and overriding configuration

Compose copies configurations from the original service over to the local one,
except for links and volumes_from. These exceptions exist to avoid
implicit dependencies—you always define links and volumes_from
locally. This ensures dependencies between services are clearly visible when
reading the current file. Defining these locally also ensures changes to the
referenced file don't result in breakage.

If a configuration option is defined in both the original service and the local
service, the local value either _override_s or _extend_s the definition of the
original service. This works differently for other configuration options.

For single-value options like image, command or mem_limit, the new value
replaces the old value. This is the default behaviour - all exceptions are
listed below.
In the case of build and image, using one causes Compose to
discard the other.

# original servicebuild: .# local serviceimage: redis# resultimage: redis
# original serviceimage: redis# local servicebuild: .# resultbuild: .

For the multi-value optionsports, expose, external_links, dns and
dns_search, Compose concatenates both sets of values:

# original serviceexpose:
- "3000"# local serviceexpose:
- "4000"
- "5000"# resultexpose:
- "3000"
- "4000"
- "5000"

In the case of environment, Compose "merges" entries together with
locally-defined values taking precedence:

# original serviceenvironment:
- FOO=original
- BAR=original# local serviceenvironment:
- BAR=local
- BAZ=local# resultenvironment:
- FOO=original
- BAR=local
- BAZ=local

Finally, for volumes, Compose "merges" entries together with locally-defined
bindings taking precedence:

# original servicevolumes:
- /original-dir/foo:/foo
- /original-dir/bar:/bar# local servicevolumes:
- /local-dir/bar:/bar
- /local-dir/baz/:baz# resultvolumes:
- /original-dir/foo:/foo
- /local-dir/bar:/bar
- /local-dir/baz/:baz

Signed-off-by: Aanand Prasad <aanand.prasad@gmail.com>
@aanand

Copy link
Copy Markdown
Author

@moxiegirl Thanks! I've incorporated your changes.

@bfirsh

Copy link
Copy Markdown

LGTM

bfirsh added a commit that referenced this pull request Apr 8, 2015
Add tutorial and reference for `extends`
@bfirsh
bfirsh merged commit a1cd00e into docker:masterApr 8, 2015
yuval-k pushed a commit to yuval-k/compose that referenced this pull request Apr 10, 2015
Add tutorial and reference for `extends`
Signed-off-by: Yuval Kohavi <yuval.kohavi@gmail.com>
yuval-k pushed a commit to yuval-k/compose that referenced this pull request Apr 10, 2015
Add tutorial and reference for `extends`
Signed-off-by: Yuval Kohavi <yuval.kohavi@gmail.com>
infraAnchor pushed a commit to infraAnchor/compose that referenced this pull request Mar 6, 2026
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.24.0 to 0.25.0.
- [Commits](golang/net@v0.24.0...v0.25.0)
---
updated-dependencies:
- dependency-name: golang.org/x/net
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Write how-to guides on how to use "extends"

3 participants

@aanand@bfirsh@moxiegirl
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Add tutorial and reference for extends - #1251

Merged
bfirsh merged 1 commit into
docker:masterfrom
aanand:extends-guide
Apr 8, 2015
Merged

Add tutorial and reference for extends#1251
bfirsh merged 1 commit into
docker:masterfrom
aanand:extends-guide

Conversation

@aanand

Copy link
Copy Markdown

Closes#1111 and #1127.

@aanandaanand added this to the 1.2.0 milestone Apr 3, 2015
@bfirsh

Copy link
Copy Markdown

Nice. LGTM

cc @moxiegirl

Comment threaddocs/extends.md

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, there are some awkward constructions in here. Generally, readers use technical documents to perform tasks or gather information. For readers, these activities take place in the present. Therefore, the present tense is appropriate in most cases.

Also the first person plural "We" is awkward and generally avoided. You should instead use "you" to bring the action closer to the reader.

Finally, your walkthrough benefits from steps to make it easier to follow:

https://gist.github.com/moxiegirl/190be92c1aac21835b01

--->
page_title: Extending services in Compose
page_description: How to use Docker Compose's "extends" keyword to share configuration between files and projects
page_keywords: fig, composition, compose, docker, orchestration, documentation, docs

Extending services in Compose

Docker Compose's extends keyword enables sharing of common configurations
among different files, or even different projects entirely. Extending services
is useful if you have several applications that reuse commonly-defined services.
Using extends you can define a service in one place and refer to it from
anywhere.

Alternatively, you can deploy the same application to multiple environments with
a slightly different set of services in each case (or with changes to the
configuration of some services). Moreover, you can do so without copy-pasting
the configuration around.

Understand the extends configuration

When defining any service in docker-compose.yml, you can declare that you are
extending another service like this:

web:
extends:
file: common-services.ymlservice: webapp

This instructs Compose to re-use the configuration for the webapp service defined in the common-services.yml file. Suppose that
common-services.yml looks like this:

webapp:
build: .ports:
- "8000:8000"volumes:
- "/data"

In this case, you'll get exactly the same result as if you wrote
docker-compose.yml with that build, ports and volumes configuration
defined directly under web.

You can go further and define (or re-define) configuration locally in
docker-compose.yml:

web:
extends:
file: common-services.ymlservice: webappenvironment:
- DEBUG=1cpu_shares: 5

You can also write other services and link your web service to them:

web:
extends:
file: common-services.ymlservice: webappenvironment:
- DEBUG=1cpu_shares: 5links:
- dbdb:
image: postgres

For full details on how to use extends, refer to the reference.

Example use case

In this example, you repurpose the example app from the quick start
guide
. (If you're not familiar with Compose, it's recommended that
you go through the quick start first.) This example assumes you want to use
Compose both to develop an application locally and then deploy it to a
production environment.

The local and production environments are similar, but there are some
differences. In development, you mount the application code as a volume so that
it can pick up changes; in production, the code should be immutable from the
outside. This ensures it’s not accidentally changed. The development environment
uses a local Redis container, but in production another team manages the Redis
service which is listening at redis-production.example.com.

To configure with extends for this sample, you must:

  1. Define the web application as a Docker image and Compose service.

  2. Define the development environment in another Compose file.

    • Use the extends to pull in the web service
    • Configure a volume to enable code reloading.
    • Create an additional Redis service for the application to use locally.
  3. Define the production environment in a third Compose file.

    In this file, you also use extends to pull in the web service and configure
    it to talk to the external, production Redis service.

Define the web app

Defining the web application requires the following:

  1. Create an app.py file.

    This files contains a simple Python application that uses Flask to serve HTTP
    and increments a counter in Redis:

    ```python
    from flask import Flask
    from redis import Redis
    import os
    app = Flask(__name__)
    redis = Redis(host=os.environ['REDIS_HOST'], port=6379)
    @app.route('/')
    def hello():
    redis.incr('hits')
    return 'Hello World! I have been seen %s times.' % redis.get('hits')
    if __name__ == "__main__":
    app.run(host="0.0.0.0", debug=True)
    ```
    

    This code uses a REDIS_HOST environment variable to determine where to find
    Redis.

  2. Define the Python dependencies a requirements.txt file.

    flask
    redis
    
  3. Create a Dockerfile to build an image containing the app:

    FROM python:2.7 ADD . /code WORKDIR /code RUN pip install -r
    requirements.txt CMD python app.py
    
  4. Create a Compose configuration file called common.yml file.

    This configuration defines how to run the app.

    web:
    build: .
    ports:
    - "5000:5000"
    

    Typically, you would have dropped this configuration into a
    docker-compose.yml file, but to use with extends it needs to be in its own
    file.

  5. Save a close all the new files.

Define the development environment

Your define your development environment in a docker-compose.yml file:

  1. Edit the file and add an extends section.

    This section pulls in the web service from the common.yml file you created
    in the previous section.

    web:
    extends:
    file: common.yml
    service: web
    volumes:
    - .:/code
    links:
    - redis
    environment:
    - REDIS_HOST=redis
    redis:
    image: redis
    

    The new addition defines a web service that:

    • Fetches the base configuration for web out of common.yml
    • Adds volumes and links configuration to the base (common.yml)
      configuration.
    • Sets the REDIS_HOST environment variable to point to the linked redis
      container. This environment uses a stock redis image from the Docker Hub.
  2. Run docker-compose up.

    Compose creates, links, and starts a web and redis container linked together.
    It mounts your application code inside the web container.

  3. Verify that the code is mounted by changing the message in
    app.py—say, from Hello world! to Hello from Compose!.

    Don't forget to refresh your browser to see your change!

Define the production environment

You are almost done. Now, define your production environment:

  1. Create a production.yml file.

    web:
    extends:
    file: common.yml
    service: web
    environment:
    - REDIS_HOST=redis-production.example.com
    
  2. Run docker-compose -f production.yml up.

    Compose creates just a web container and configures the Redis connection via
    the REDIS_HOST environment variable. This variable points to the production
    Redis instance.

    Note: If you try to load up the webapp in your browser you'll get an
    error—redis-production.example.com isn't actually a Redis server.

You've now done a basic extends configuration. As your application develops,
you can make any necessary changes to the web service in common.yml. Compose
picks up both the development and production environments when you next run
docker-compose. You don't have to do any copy-and-paste, and you don't have to
manually keep both environments in sync.

Reference

You can use extends on any service together with other configuration keys. It
always expects a dictionary that should always contain two keys: file and
service.

The file key specifies which file to look in. It can be an absolute path or a
relative one—if relative, it's treated as relative to the current file.

The service key specifies the name of the service to extend, for example web or database.

You can extend a service that itself extends another. You can extend indefinitely. Compose does not support circular references and docker-compose returns an error if it encounters them.

Adding and overriding configuration

Compose copies configurations from the original service over to the local one,
except for links and volumes_from. These exceptions exist to avoid
implicit dependencies—you always define links and volumes_from
locally. This ensures dependencies between services are clearly visible when
reading the current file. Defining these locally also ensures changes to the
referenced file don't result in breakage.

If a configuration option is defined in both the original service and the local
service, the local value either _override_s or _extend_s the definition of the
original service. This works differently for other configuration options.

For single-value options like image, command or mem_limit, the new value
replaces the old value. This is the default behaviour - all exceptions are
listed below.
In the case of build and image, using one causes Compose to
discard the other.

# original servicebuild: .# local serviceimage: redis# resultimage: redis
# original serviceimage: redis# local servicebuild: .# resultbuild: .

For the multi-value optionsports, expose, external_links, dns and
dns_search, Compose concatenates both sets of values:

# original serviceexpose:
- "3000"# local serviceexpose:
- "4000"
- "5000"# resultexpose:
- "3000"
- "4000"
- "5000"

In the case of environment, Compose "merges" entries together with
locally-defined values taking precedence:

# original serviceenvironment:
- FOO=original
- BAR=original# local serviceenvironment:
- BAR=local
- BAZ=local# resultenvironment:
- FOO=original
- BAR=local
- BAZ=local

Finally, for volumes, Compose "merges" entries together with locally-defined
bindings taking precedence:

# original servicevolumes:
- /original-dir/foo:/foo
- /original-dir/bar:/bar# local servicevolumes:
- /local-dir/bar:/bar
- /local-dir/baz/:baz# resultvolumes:
- /original-dir/foo:/foo
- /local-dir/bar:/bar
- /local-dir/baz/:baz

Signed-off-by: Aanand Prasad <aanand.prasad@gmail.com>
@aanand

Copy link
Copy Markdown
Author

@moxiegirl Thanks! I've incorporated your changes.

@bfirsh

Copy link
Copy Markdown

LGTM

bfirsh added a commit that referenced this pull request Apr 8, 2015
Add tutorial and reference for `extends`
@bfirsh
bfirsh merged commit a1cd00e into docker:masterApr 8, 2015
yuval-k pushed a commit to yuval-k/compose that referenced this pull request Apr 10, 2015
Add tutorial and reference for `extends`
Signed-off-by: Yuval Kohavi <yuval.kohavi@gmail.com>
yuval-k pushed a commit to yuval-k/compose that referenced this pull request Apr 10, 2015
Add tutorial and reference for `extends`
Signed-off-by: Yuval Kohavi <yuval.kohavi@gmail.com>
infraAnchor pushed a commit to infraAnchor/compose that referenced this pull request Mar 6, 2026
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.24.0 to 0.25.0.
- [Commits](golang/net@v0.24.0...v0.25.0)
---
updated-dependencies:
- dependency-name: golang.org/x/net
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Write how-to guides on how to use "extends"

3 participants

@aanand@bfirsh@moxiegirl