4.2.2 WORKDIR
A focused guide to WORKDIR, connecting core concepts with practical Docker and container operations.
WORKDIR sets the working directory for any subsequent instructions in a Dockerfile, and also determines the directory a container's main process starts in by default, providing a consistent reference point for relative paths used throughout the rest of the build and at runtime.
Setting a Working Directory
WORKDIR both creates the specified directory if it does not already exist and changes the current directory for every instruction that follows it.
WORKDIR /app
COPY . .
RUN npm install
CMD ["node", "server.js"]
Because WORKDIR /app was set first, the COPY instruction places files into /app, and npm install runs as if executed from within that directory.
Why WORKDIR Is Preferred Over Using RUN cd
Using RUN cd /app does not have a persistent effect on later instructions, since each RUN instruction executes in its own separate shell invocation — WORKDIR is the correct way to persistently change directory across the rest of the Dockerfile.
RUN cd /app && npm install
WORKDIR /app
RUN npm install
The second approach correctly persists the working directory for every subsequent instruction, while the first only affects the single RUN instruction it appears in.
Using WORKDIR Multiple Times
WORKDIR can be specified more than once in the same Dockerfile, with each instance changing the current directory for everything that follows it, which is useful when a build genuinely needs to work across multiple distinct directories.
WORKDIR /build
COPY src/ .
RUN make
WORKDIR /app
COPY --from=0 /build/output .
WORKDIR's Effect at Runtime
Beyond affecting the build itself, the last WORKDIR set in the Dockerfile becomes the directory a container's main process starts in when the container runs, which is relevant for any relative file paths the application itself might use.
docker run --rm myapp pwd
Why WORKDIR Matters
Using WORKDIR explicitly, rather than relying on relative paths without a clearly established reference point, makes a Dockerfile's behavior more predictable and easier to reason about, both during the build and once a container is actually running.