Before a build starts, the whole context directory is sent to the daemon. Without a .dockerignore that includes .git, node_modules and every previous build artefact — commonly hundreds of megabytes copied before the first instruction runs.
.git
.gitignore
node_modules
vendor
*.log
*.sql
.env
docker-compose.yml
Besides the time, there is a correctness reason: COPY . /app will happily bake .env and .git into the image, and both then ship to wherever that image goes. The syntax resembles .gitignore but is not identical — negation with ! behaves differently and there is no per-directory file. Watch the “Sending build context” line; if it is large, this is why.