SSD Nodes Learn Hosting plans →
Guides Matt ConnorBy Matt Connor

Run just one service with Docker Compose

Update one container in a multi-service stack: docker compose up -d web, why depends_on still starts, --no-deps, start vs up, stop, and --scale.

Run one service with Docker Compose

Docker Compose acts on a single service the moment you name it: docker compose up -d api reconciles the api container and leaves every other container in the stack running. That is the command you want after changing one image tag, or one environment variable, in a stack of four or five services on one VPS. A change that touches one service does not need the whole stack to bounce.

Two notes before the commands. Every example uses Compose v2 syntax, docker compose with a space, because the old v1 docker-compose binary is gone and no longer gets fixes. If your server still has the hyphenated one, replacing it is the first job, and what actually happened to the docker-compose command covers that swap. Also run each command from the directory holding your compose.yaml, or pass -f /path/to/compose.yaml, because Compose works out which project you mean from the file it reads. Run the commands below against your own stack as you read. Your output is the authority here, not my description of it.

The stack these examples use

services:
  web:
    image: caddy:2
    ports:
      - "80:80"
      - "443:443"
    depends_on:
      - api
  api:
    image: ghcr.io/example/api:1.4.0
    env_file: .env
    depends_on:
      db:
        condition: service_healthy
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/pg
    volumes:
      - dbdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5
  cache:
    image: redis:7
volumes:
  dbdata:

Four services. web needs api, api needs db, and cache stands on its own. Hold that shape in mind, because depends_on decides how much of the stack one named service drags up with it. The database password lives outside the file, which is the habit described in keeping credentials in an env file instead of the compose file.

What does docker compose up -d api do to the rest of the stack?

It creates or replaces the container for api. It also brings up whatever api lists under depends_on, so db starts if it is not already running. It does not touch web, even though web depends on api, because Compose walks dependencies downward and not dependents upward. It does not touch cache, which nothing in that chain names.

Whether the api container was replaced or left alone depends on what changed since it was created, and you should read that from your own machine rather than trust a sentence in a guide. Record the container id first, run the command, then compare.

docker compose ps -q api
docker compose up -d api
docker compose ps -q api
docker compose ps -a

A different id on the second read means Compose destroyed the old container and created a new one from the current file. The same id means it decided nothing needed doing. docker compose ps -a adds the containers that are not running, which is the view you want when a service exited seconds after starting and the plain ps no longer lists it.

When a dependency carries condition: service_healthy, as db does above, up waits for that health check to pass before it starts the dependent service. So a targeted up -d api can sit there for a while, and what it is waiting for is the database probe, not the API. The rules for what that probe must return, and how long Compose waits, are in how a Compose health check gates a dependent service.

When should I use --no-deps?

docker compose up -d --no-deps api replaces the api container and starts nothing else. Use it when you know the database and the rest of the chain are already up, which is the normal case for a routine image bump on a running server. It is also the honest flag when a dependency is slow to probe and you do not want to wait on a health check for a container that never stopped.

docker compose up -d --no-deps api
docker compose ps

The cost is that --no-deps removes a safety net. If db is in fact stopped, Compose still starts api, and api then fails its first database connection. What it prints depends on the client library it uses, so read docker compose logs --tail 50 api rather than expecting a particular string. Confirm the dependency yourself with docker compose ps before you reach for the flag.

Why docker compose start api is not the same as up

docker compose start api resumes a container that already exists and is stopped. It never creates a container, and it never applies an edit you made to the compose file, because the container it resumes was built from the configuration that was current when it was created. If no container exists for that service, there is nothing for start to resume, and Compose says so instead of building one.

That single difference decides which command you want. Edited the file, or pulled a new tag? Use up -d <service>, which compares the desired state in the file against the container that exists. Stopped a service an hour ago and want it back exactly as it was? Use start <service>, which is faster and changes nothing.

docker compose stop api
docker compose ps -q api
docker compose start api
docker compose ps -q api

The id survives a stop and start pair, because the container was paused and resumed rather than rebuilt. docker compose restart api behaves the same way on this point: it cycles the existing container with its existing configuration, which is why a restart never picks up a changed image tag. Restarting a service against rebuilding it works through that distinction with the cases where each one is correct.

How do I leave an existing container alone?

--no-recreate tells up to start what is missing and to leave any container that already exists exactly where it is, even when the file no longer matches it. It is most useful on the whole project rather than on one service: docker compose up -d --no-recreate fills in the containers that are absent after a reboot or a manual rm, without disturbing the ones still running.

docker compose up -d --no-recreate
docker compose ps -a

The opposite flag is --force-recreate, which destroys and rebuilds the container even when Compose sees no reason to. Reach for it when a container has drifted from the file because somebody changed it by hand, or when you want to be sure a fresh filesystem layer is in play. Both flags accept a service name, so docker compose up -d --force-recreate --no-deps api is a valid and quite specific instruction: rebuild this one container, touch nothing else.

Applying a new image tag to one service

Changing the tag in the file is only half the work, because up uses the image already on the box if a matching tag is present locally. Pull first, then reconcile the one service.

docker compose pull api
docker compose up -d --no-deps api
docker compose ps
docker compose logs --tail 50 api

Read docker compose ps for the new container, then read the logs for the first fifty lines of the new process. A container that shows as running has passed nothing except the act of starting, so the log tail is where you learn whether the new version actually came up. The previous image stays on disk under its old tag, which is what makes a rollback cheap: put the old tag back in the file and run the same two commands.

If the service builds from a Dockerfile rather than pulling a published image, the equivalent is docker compose up -d --build api, and the difference between those two paths is the subject of building an image in your compose file against pulling one.

Stopping one service without taking the stack down

docker compose stop cache stops that container and leaves everything else in place: the container itself, the project network, the volumes, and the other services. There is no docker compose down cache, because down is a project-level command that removes containers and the default network for the entire stack. The service-scoped counterparts are stop, which keeps the container, and rm, which deletes a container that is already stopped.

docker compose stop cache
docker compose ps -a
docker compose rm cache

docker compose rm asks for confirmation before it deletes, and -f skips the prompt. Removing a container does not remove its named volume, so database data survives this. What down removes that stop leaves behind covers the project-wide version of the same choice.

Stopping a service that others depend on has no effect on those others at the moment you stop it. They keep running and start failing their next request to it. Compose does not cascade a stop upward, so you have to decide for yourself whether pausing db for two minutes is acceptable to api.

Running more than one copy with --scale

--scale sets how many containers a service runs, for this invocation only.

docker compose up -d --no-deps --scale api=3 api
docker compose ps

Two things in a compose file block this, and both fail for a reason you can see. A service with a container_name cannot scale, because that name is fixed and two containers cannot hold the same name. A service publishing a fixed host port, such as "8080:8080", cannot scale past one container, because only one process can bind a given host port. The fix for the second is a port range like "8080-8082:8080", or, better on a real server, to publish no host port at all and put a reverse proxy in front. The proxy reaches the replicas through the service name on the project network, and how Compose resolves service names on its own network explains what that name returns when several containers answer to it.

The count is not written to your file. Run a plain docker compose up -d afterwards and read docker compose ps to see how many containers Compose leaves you with. If the higher number is meant to be permanent, put deploy: replicas: 3 under the service instead of passing the flag each time.

When is one service the wrong thing to target?

Targeting one service is right when the change is contained in that service. A new image tag on a stateless web or worker container. One environment variable on one process. A crashed service that needs bringing back while the rest of the stack keeps serving. Adding a replica during a busy hour. In each case the blast radius of the command matches the blast radius of the edit, and that is the whole test.

A full docker compose up -d with no service name is the honest answer in three situations. The first is a change that is not owned by one service: a shared env_file, a top-level networks or volumes block, a YAML anchor that several services extend. Compose applies those where they are used, so naming one service applies half of your edit and leaves the rest of the stack on the old definition, which is the worst of both outcomes. The second is a change to a dependency that its dependents read once at startup, such as a rotated database password. Both sides have to come up again, in order, or the running client keeps presenting a credential the server no longer accepts. The third is drift: the containers on the box have been patched by hand over several weeks and nobody can say which one still matches the file. A whole-project up -d is cheap to reason about, and on a personal VPS at a quiet hour the few seconds of downtime cost less than the uncertainty.

The judgement is about coupling, not about flags. Ask what else reads the thing you changed. If the answer is nothing, name the service. If the answer is the database, or the proxy, or every service that shares the env file, recreate the project and watch it come up in dependency order. The wider list of Compose commands and their flags is worth keeping open while you work, and if this stack is your first one on a server, running a Compose stack on a VPS from the beginning sets up the file these commands operate on.

FAQ

Does docker compose up -d api restart my other services?

It does not restart services that sit above api, so web and anything else depending on api keep running untouched. It does bring up the services api lists under depends_on, starting them if they are stopped, because Compose cannot honour the dependency otherwise. Services outside that dependency chain are left alone. Run docker compose ps -a before and after to see which containers changed state on your own stack.

What is the difference between docker compose start and docker compose up?

start only resumes a container that already exists and is stopped. It creates nothing, and it ignores edits you made to the compose file, because it is restarting a container that was built from the older configuration. up compares the file against what exists and creates or replaces containers so the two agree. After editing the file, use up -d <service>. After a plain stop, start <service> is enough.

How do I update one container after changing its image tag?

Run docker compose pull <service> to fetch the new tag, then docker compose up -d --no-deps <service> to replace that container alone. Check docker compose ps -q <service> before and after: a changed container id confirms the replacement happened. Then read docker compose logs --tail 50 <service>, because a container that starts has not yet proved that the new version works.

Why does --scale fail on one of my services?

Two settings in the file make a service unscalable. A container_name fixes the container's name, and two containers cannot share one name. A fixed published port such as "8080:8080" can be bound by only one container on the host. Remove the container_name, and either publish a port range or publish nothing and route to the replicas through a reverse proxy on the project network.

Can I stop one service without running docker compose down?

Yes. docker compose stop <service> stops that container and leaves the rest of the project, its network and its volumes in place. down has no service argument because it operates on the whole project. If you also want the stopped container deleted, follow with docker compose rm <service>, which leaves named volumes untouched.