When a Dockerfile copies source with COPY . ., git submodules appear as empty directories. Git submodules are tracked by reference (a commit SHA in .gitmodules), not by content. Docker's build context does not include .git/ metadata, so there is nothing to resolve the submodule from.
# Submodule directory will be EMPTY after this
COPY . .
# Fix: clone the submodule content directly if missing
RUN if [ ! "$(ls src/content/blog/*.mdx 2>/dev/null)" ]; then \
echo "Fetching content..." && \
apk add --no-cache git && \
git clone --depth 1 \
"https://x-access-token:${GITHUB_TOKEN}@github.com/user/content.git" \
src/content && \
rm -rf src/content/.git; \
fi
The pattern: check if the submodule directory has the expected files. If not, clone it with --depth 1 (shallow, fast) using a GitHub token passed as a build arg. Remove .git/ after cloning to keep the image small.
This applies to every submodule independently. If you have three submodules (content, prompts, til), you need three separate clone fallback blocks.
Alternative: use git clone --recursive in CI before docker build, so the build context already has submodule contents. But this requires CI to have git access, which is not always the case with managed platforms like Dokploy.
Git Submodules Are Not Cloned in Docker Builds
When a Dockerfile copies source with
COPY . ., git submodules appear as empty directories. Git submodules are tracked by reference (a commit SHA in.gitmodules), not by content. Docker's build context does not include.git/metadata, so there is nothing to resolve the submodule from.The pattern: check if the submodule directory has the expected files. If not, clone it with
--depth 1(shallow, fast) using a GitHub token passed as a build arg. Remove.git/after cloning to keep the image small.This applies to every submodule independently. If you have three submodules (
content,prompts,til), you need three separate clone fallback blocks.Alternative: use
git clone --recursivein CI beforedocker build, so the build context already has submodule contents. But this requires CI to have git access, which is not always the case with managed platforms like Dokploy.