π§© The Problem
You have multiple (group) projects (frontend, backend, etc.) and you want:
- A single Dockerfile in a central repo (
cicd-template/frontend/gitlab-template.yml) - All group app repos reuse it
- No duplication, no drift, better control
You try:
include:
- project: "kelvyn-labs/cicd-template"
ref: master
file: "/frontend/gitlab-ci.yml"
But during the pipeline:
docker build -f frontend/Dockerfile .
π β It fails β file not found
π§ Why This Happens
In GitLab:
include:projectonly imports CI YAML, not repository files
Your pipeline still runs inside:
nextjs-cicd-template
So it cannot access files from:
cicd-template
β Common (Wrong) Solutions
- Copy Dockerfile into every repo β
- Use Git submodules β (heavy, messy)
- Assume
includegives file access β
β The Correct Solution
Use:
CI_JOB_TOKEN+ GitLab Repository Files APIWhen a CI/CD pipeline job is about to run, GitLab generates a unique token and makes it available to the job as the CI_JOB_TOKEN predefined variable. The token is valid only while the job is running. After the job finishes, the token access is revoked and you cannot use the token anymore.
This allows your pipeline to securely fetch files from another project at runtime.
π How It Works
Pipeline (app repo)
β
CI_JOB_TOKEN (auth)
β
GitLab API
β
cicd-template repo
β
Download Dockerfile
π§ͺ Implementation
Step 1 β Allow Cross-Project Access
In cicd-template:
Settings β CI/CD β Job token permissions -> Fine-grained permissions -> Add kelvyn-labs/nextjs-cicd-template
Source:
https://docs.gitlab.com/ci/jobs/fine_grained_permissions/#repositories-endpoints
Step 2 β Fetch Dockerfile
.build-job:
variables:
CICD_TEMPLATE_PROJECT_ID: "81568045" // project ID
CICD_TEMPLATE_REF: "master" // target branch
CICD_TEMPLATE_DOCKERFILE_PATH: "frontend%2FDockerfile" // encode url
script:
- echo "Fetch Dockerfile from cicd-template"
- 'curl --fail --location --header "JOB-TOKEN: $CI_JOB_TOKEN" "https://gitlab.com/api/v4/projects/$CICD_TEMPLATE_PROJECT_ID/repository/files/$CICD_TEMPLATE_DOCKERFILE_PATH/raw?ref=$CICD_TEMPLATE_REF" -o Dockerfile'
β οΈ Important Notes
- File path must be URL-encoded
frontend/Dockerfile β frontend%2FDockerfile
- Use project ID (simpler than encoding path)
- Token only works while job is running
- Target repo must allow access (allowlist)
Step 3 β Build Image
docker buildx build \
--file Dockerfile \
--tag $IMAGE_TAG \
--push .
π§ Why This Is Better
β Centralized Control
- Dockerfile lives in one repo
- Platform team controls build logic
β No Duplication
- No copy-paste across repos
β Secure
-
Controlled via:
- allowlist
- user permissions
- CI_JOB_TOKEN scope
β Flexible
- Works for FE / BE / any service
π Advanced Tips
1. Pin Version (Donβt Use master)
variables:
CICD_TEMPLATE_REF: "v1.0.0"
...?ref=${CICD_TEMPLATE_REF}
2. Make It Reusable
variables:
CICD_TEMPLATE_PROJECT_ID: "81568045"
CICD_TEMPLATE_DOCKERFILE: "frontend%2FDockerfile"
3. When NOT to Use This
If your Dockerfile depends on multiple files:
COPY scripts/start.sh /app/
π Then use git clone instead of single-file fetch
π Final Takeaway
includeis for config reuse
CI_JOB_TOKENis for secure runtime access
If you want to reuse real files across projects:
π use GitLab API + CI_JOB_TOKEN
π¬ Closing
This pattern is used by many teams to build:
- Internal CI/CD platforms
- Standardized pipelines
- Centralized build logic
If youβve ever struggled with:
βWhy canβt my pipeline access files from another repo?β
Now you know the missing piece.
π₯ Bonus Thought
Stop copying Dockerfiles.
Start treating CI/CD like a platform.
Full source codes:

Top comments (0)