[Docker](https://www.docker.com/) provides two good options for moving your code into an image or container: [bind mounts](https://docs.docker.com/storage/bind-mounts/) and the [Dockerfile](https://docs.docker.com/engine/reference/builder/#copy) `[COPY](https://docs.docker.com/engine/reference/builder/#copy)` [instruction](https://docs.docker.com/engine/reference/builder/#copy). In this post, I'll explain why images should always use the `COPY` instruction in production, and why it may be more convenient to use bind mounts in development.\n\n### Dockerfile `COPY` Instruction\n\nThe `COPY` instruction in a Dockerfile is used to copy files or directories from the host machine filesystem into an image. For example, the following Dockerfile sets up a NodeJS application for running in production mode.\n\n\\# Dockerfile \nFROM node:carbon\n\nWORKDIR /app \nENV NODE\\_ENV=production\n\n\\# Install dependencies first to take advantage of Docker layer caching. \nCOPY package.json yarn.lock ./ \nRUN yarn install --frozen-lockfile --no-cache --production\n\n\\# Copy the application files into the image. \nCOPY . .\n\nEXPOSE 3000 \nCMD \\[ "node", "app.js" \\]\n\nBuild and run:\n\n$ docker build -t myapp . \n$ docker run -d -p 3000:3000 myapp\n\nThe `COPY` instruction recursively copies files and directories from the host into an image, which means that sensitive files may also be copied in. Similar to Git’s `.gitignore`, Docker’s `[.dockerignore](https://docs.docker.com/engine/reference/builder/#dockerignore-file)` [file](https://docs.docker.com/engine/reference/builder/#dockerignore-file) allows you to prevent certain files from being copied into the image. You should **always include a** `**.dockerignore**` **file when using the** `**COPY**` **instruction**. At minimum, it should include files related to your version control system and locally installed dependencies. A typical NodeJS application, for example, might use the following.\n\n\\# .dockerignore \n.git \nDockerfile \n.dockerignore \nnode\\_modules \nnpm-debug.log\n\n### Bind Mounts\n\nA bind mount allows you to mount a file or directory from the host machine into the container. In the below snippet, the working directory is mounted and accessible from `/app` within the container. Once the container is running, you can interact with it through a shell.\n\n$ docker run --rm -it -p 3000:3000 -v $(pwd):/app myapp bash \nroot@id:/app# yarn global add nodemon \nroot@id:/app# nodemon app.js\n\n`nodemon` is a tool that watches for file changes and automatically restarts the application when changes are detected. In the above example, when you change files on the host machine, those changes are automatically visible in the container via the bind mount, and your app will automatically by restarted by `nodemon`.\n\n### Picking Between the `COPY` Instruction and Bind Mounts\n\nWhen should you use the `COPY` instruction, and when is appropriate to use a bind mount?\n\n**Bind mounts are great for local development**. They provide convenience through the fact that changes to the host’s development environment and code are immediately reflected within the container, and files that the application creates in the container, like build artifacts or a log file, become available from the host.\n\nHowever, bind mounts do come with some security concerns. From the [Docker storage documentation](https://docs.docker.com/storage/):\n\n> _One side effect of using bind mounts, for better or for worse, is that you can change the host filesystem via processes running in a container, including creating, modifying, or deleting important system files or directories. This is a powerful ability which can have security implications, including impacting non-Docker processes on the host system._\n\n> _\\[…\\]_\n\n> _If you use Docker for development this way, your production Dockerfile would copy the production-ready artifacts directly into the image, rather than relying on a bind mount._\n\nA bind mount exposes the host system to the container, and reduces the security and isolation of the container. Even a [read-only bind mount](https://docs.docker.com/storage/bind-mounts/#use-a-read-only-bind-mount) can expose files that would otherwise be excluded from the image by `.dockerignore`. To avoid these issues **in production, the** `**COPY**` **command should be used to transfer code** into the image, and not a bind mount.\n\n### Further Reading\n\nThe [Docker documentation](https://docs.docker.com/storage/) provides details on other mount types, and gives additional detail on their possible use cases. In particular, there are certain use cases where it can be advantageous to use a bind mount for configuration files.\n\nAnd really, [do not ignore](https://codefresh.io/docker-tutorial/not-ignore-dockerignore/) `[.dockerignore](https://codefresh.io/docker-tutorial/not-ignore-dockerignore/)`.