frontend:
image: node:lts
volumes:
- myapp:/home/node/app
volumes:
myapp:
```
Running `docker compose up` for the first time creates a volume. Docker reuses the same volume when you run the command subsequently.
You can create a volume directly outside of Compose using `docker volume create` and
then reference it inside `compose.yaml` as follows:
```yaml
services:
frontend:
image: node:lts
volumes:
- myapp:/home/node/app
volumes:
myapp:
external: true
```
For more information about using volumes with Compose, refer to the
[Volumes](/reference/compose-file/volumes.md)
section in the Compose specification.
### Start a service with volumes
When you start a service and define a volume, each service container uses its own
local volume. None of the containers can share this data if you use the `local`
volume driver. However, some volume drivers do support shared storage.
The following example starts an `nginx` service with four replicas, each of which
uses a local volume called `myvol2`.
```console
$ docker service create -d \
--replicas=4 \
--name devtest-service \
--mount source=myvol2,target=/app \
nginx:latest
```
Use `docker service ps devtest-service` to verify that the service is running:
```console
$ docker service ps devtest-service
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
4d7oz1j85wwn devtest-service.1 nginx:latest moby Running Running 14 seconds ago
```
You can remove the service to stop the running tasks:
```console
$ docker service rm devtest-service
```
Removing the service doesn't remove any volumes created by the service.
Volume removal is a separate step.
### Populate a volume using a container
If you start a container which creates a new volume, and the container
has files or directories in the directory to be mounted such as `/app/`,
Docker copies the directory's contents into the volume. The container then
mounts and uses the volume, and other containers which use the volume also
have access to the pre-populated content.
To show this, the following example starts an `nginx` container and
populates the new volume `nginx-vol` with the contents of the container's
`/usr/share/nginx/html` directory. This is where Nginx stores its default HTML
content.
The `--mount` and `-v` examples have the same end result.
{{< tabs >}}
{{< tab name="`--mount`" >}}
```console
$ docker run -d \
--name=nginxtest \
--mount source=nginx-vol,destination=/usr/share/nginx/html \
nginx:latest
```
{{< /tab >}}
{{< tab name="`-v`" >}}
```console
$ docker run -d \
--name=nginxtest \
-v nginx-vol:/usr/share/nginx/html \
nginx:latest
```
{{< /tab >}}
{{< /tabs >}}
After running either of these examples, run the following commands to clean up
the containers and volumes. Note volume removal is a separate step.
```console
$ docker container stop nginxtest
$ docker container rm nginxtest
$ docker volume rm nginx-vol
```
## Use a read-only volume
For some development applications, the container needs to write into the bind
mount so that changes are propagated back to the Docker host. At other times,
the container only needs read access to the data. Multiple
containers can mount the same volume. You can simultaneously mount a
single volume as `read-write` for some containers and as `read-only` for others.
The following example changes the previous one. It mounts the directory as a read-only
volume, by adding `ro` to the (empty by default) list of options, after the
mount point within the container. Where multiple options are present, you can separate
them using commas.
The `--mount` and `-v` examples have the same result.
{{< tabs >}}
{{< tab name="`--mount`" >}}
```console
$ docker run -d \
--name=nginxtest \
--mount source=nginx-vol,destination=/usr/share/nginx/html,readonly \
nginx:latest
```
{{< /tab >}}