Quick Answer: Dockerfile and Image Naming Rules
Naming conventions in Docker span two separate concerns: the file that defines your image, and the name/tag assigned to the image itself. Here are the core rules:
- Default filename:
Dockerfile(capital D, no extension). Docker CLI uses this automatically without a-fflag. - Variant files:
Dockerfile.dev,Dockerfile.prod,Dockerfile.test— usedocker build -f Dockerfile.prod. - Image name format:
[registry/][namespace/]name:tag— all lowercase, no spaces, alphanumeric plus hyphens and underscores. - Tag strategy: Never rely on
latestalone in production. Use semantic versioning or commit SHA tags. - Registry prefix: Docker Hub is implied (
nginx=docker.io/library/nginx). All other registries require the full prefix.
Dockerfile Filename Conventions
The Docker documentation specifies Dockerfile as the default filename. This is not arbitrary — it matches what docker build . looks for without any flags. The capital D matters on case-sensitive filesystems (Linux).
Standard Filename
# Default - docker build uses this automatically
Dockerfile
# Build command
docker build -t myapp:1.0 .
Environment-Specific Files
When you have multiple build targets for different environments, the accepted convention is to append the environment as an extension:
# Environment variants
Dockerfile.dev # Local development
Dockerfile.test # CI test runner
Dockerfile.prod # Production (optimized, no dev tools)
Dockerfile.ci # CI-specific (may differ from test)
# Usage
docker build -f Dockerfile.prod -t myapp:1.0 .
docker build -f Dockerfile.dev -t myapp:dev .
Alternative: Multi-Stage Single File
Many teams prefer a single Dockerfile with named stages rather than multiple files. This keeps all build logic in one place and avoids managing multiple files:
FROM node:20-alpine AS base
WORKDIR /app
COPY package*.json ./
RUN npm ci
FROM base AS development
RUN npm install # includes devDependencies
CMD ["npm", "run", "dev"]
FROM base AS test
RUN npm ci # only production deps already there
COPY . .
CMD ["npm", "test"]
FROM base AS production
COPY . .
RUN npm run build
USER node
CMD ["node", "dist/server.js"]
# Target a specific stage
docker build --target development -t myapp:dev .
docker build --target production -t myapp:1.0 .
Multi-stage in one file is generally preferred for smaller codebases. Separate Dockerfile variants are useful when the base image itself changes per environment (e.g., development uses a debugging-enabled base image that differs fundamentally from production).
What Not to Name Your Dockerfile
dockerfile(lowercase) — Works on macOS (case-insensitive), fails silently on Linux CI. Always use capital D.Dockerfile.dockerfile— Redundant and confusing.Dockerfile.productionvsDockerfile.prod— Pick one convention and apply it consistently across your entire organization.- Spaces in filename —
Dockerfile devrequires quoting everywhere and breaks most automation scripts.
Image Naming Conventions
Docker image names follow a structured format. Understanding each component prevents naming collisions, registry authentication errors, and confusion in CI pipelines.
Full Name Format
[registry/][namespace/]name[:tag][@digest]
# Examples
nginx # Docker Hub official image
nginx:1.26-alpine # with tag
docker.io/library/nginx:1.26 # fully qualified Docker Hub
myorg/myapp:1.2.3 # Docker Hub user/org image
ghcr.io/myorg/myapp:1.2.3 # GitHub Container Registry
registry.example.com/myapp:1.2.3 # private registry
myapp@sha256:abc123... # pinned by digest (immutable)
Name Character Rules
- Lowercase only —
MyAppis invalid. Usemyapp. - Allowed characters: a-z, 0-9, hyphens (
-), underscores (_), periods (.) - Start with alphanumeric — Cannot start with a hyphen or period.
- Maximum length: 128 characters for the name component.
- Slashes — Used to separate registry, namespace, and name. Maximum two slashes in standard usage.
Namespace Conventions
# Docker Hub official images (no namespace)
nginx
postgres
redis
# Docker Hub user/org images
mycompany/webserver
mycompany/api-gateway
# Sub-namespacing (private registry)
registry.example.com/backend/api-gateway
registry.example.com/frontend/dashboard
registry.example.com/infrastructure/base-image
Tag Strategy
Tags identify a specific version or variant of an image. Poor tagging is one of the most common causes of mysterious deployment failures ("but I didn't change anything").
The latest Problem
latest is a tag like any other — it is not automatically the most recent image. It is simply whatever image was last tagged latest. In production, using :latest means:
- You do not know exactly which version is running.
- A
docker pullcan silently change what your container runs. - Rollback requires manual intervention to identify the previous image.
- Different environments may run different images with the same tag.
# Do not do this in production
docker run myapp:latest
# Do this instead
docker run myapp:1.2.3
Semantic Versioning Tags
Semantic versioning (MAJOR.MINOR.PATCH) is the most widely adopted image tagging strategy for applications:
# Full semver tag
docker tag myapp:latest myapp:1.2.3
# Also tag the minor version (floats to latest patch)
docker tag myapp:1.2.3 myapp:1.2
# Also tag the major version (floats to latest minor)
docker tag myapp:1.2.3 myapp:1
# Update latest (if you choose to maintain it)
docker tag myapp:1.2.3 myapp:latest
This multi-tagging approach means consumers can pin to myapp:1 (gets all 1.x.y updates automatically) or myapp:1.2 (gets patch updates) or myapp:1.2.3 (immutable, specific version).
Git Commit SHA Tags
For CI/CD pipelines where you need immutable, traceable tags tied directly to code commits:
# Tag with full git SHA
docker tag myapp:latest myapp:$(git rev-parse HEAD)
# Tag with short SHA (7 characters)
docker tag myapp:latest myapp:$(git rev-parse --short HEAD)
# In CI (GitHub Actions example)
docker tag myapp:latest myapp:${{ github.sha }}
# Tag with date (useful for nightly builds)
docker tag myapp:latest myapp:$(date +%Y%m%d)
# Combined: semver + SHA for full traceability
docker tag myapp:latest myapp:1.2.3-$(git rev-parse --short HEAD)
Environment Tags
# Environment-scoped tags
myapp:1.2.3-dev
myapp:1.2.3-staging
myapp:1.2.3-prod
# Or branch-based
myapp:main-abc1234
myapp:develop-def5678
Build Context Organization
The build context is everything Docker sends to the daemon for the build. Poor organization leads to slow builds and unintentional file inclusion.
.dockerignore
Always include a .dockerignore file at the root of your build context. The format mirrors .gitignore:
# .dockerignore
.git
.gitignore
.env
.env.*
node_modules
npm-debug.log
*.md
README*
tests/
docs/
.DS_Store
__pycache__
*.pyc
*.pyo
dist/
build/
coverage/
.coverage
Without .dockerignore, Docker sends the entire build context — including .git (which can be hundreds of megabytes for older repos) — to the daemon on every build. This dramatically slows build times.
Multi-Stage Build Naming
For multi-stage builds, name your stages explicitly. Named stages make the build intent clear and allow partial builds:
FROM golang:1.24-alpine AS builder
WORKDIR /build
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o app ./cmd/server
FROM alpine:3.20 AS security-scan
# Optional scan stage
COPY --from=builder /build/app /app
FROM scratch AS final
COPY --from=builder /build/app /app
ENTRYPOINT ["/app"]
# Build only up to builder stage (useful for debugging)
docker build --target builder -t myapp:builder .
Registry-Specific Conventions
Docker Hub
- Official images: no namespace (
nginx,postgres) - Personal/org images:
username/imageororgname/image - Private repos require login:
docker login docker.io - Free tier: 1 private repo, unlimited public
GitHub Container Registry (GHCR)
# Always scoped to user or org
ghcr.io/username/imagename:tag
ghcr.io/orgname/imagename:tag
# Login
echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdin
# Push
docker push ghcr.io/myorg/myapp:1.2.3
Private Registry
# Login to private registry
docker login registry.example.com
# Full path always required
docker pull registry.example.com/team/service:1.0.0
docker push registry.example.com/team/service:1.0.0
Common Mistakes
Using Only latest in Production
As described above, latest is not a version. Use specific version tags in all production deployments, Kubernetes manifests, and docker-compose.yml files.
No Immutable Tags in CI
If your CI pipeline only pushes :latest, you lose the ability to correlate a running container to the specific commit that built it. Always tag with the commit SHA in CI in addition to any other tags.
Conflicting Names Across Registries
myapp on Docker Hub and registry.example.com/myapp are different images. If you have both, always use fully qualified names in scripts and manifests to avoid ambiguity about which registry is being used.
Uppercase in Image Names
Docker image names must be lowercase. Attempting to push MyOrg/MyApp:1.0 will fail with an error about invalid reference format. Establish a lowercase naming rule at the start of the project.
Overlong Tag Names
Tags have a maximum length of 128 characters. Combined commit SHA + branch name + build number can exceed this. Keep tags concise: short SHA (7 chars) is typically sufficient for uniqueness within a project.
TL;DR
- Default Dockerfile name is
Dockerfile(capital D). Variants use dot-notation:Dockerfile.prod,Dockerfile.dev. - Image names are lowercase, formatted as
[registry/][namespace/]name[:tag]. - Never use only
:latestin production. Tag with semantic versions (1.2.3) and/or git commit SHAs. - Always include a
.dockerignoreto exclude .git, node_modules, and other large or sensitive directories from the build context. - Use named stages in multi-stage Dockerfiles for clarity and targetability.
- Fully qualify registry URLs for any registry that is not Docker Hub.
Panelica's Docker Manager provides a visual interface for managing images, containers, and Compose stacks — including pulling from private registries, launching containers from templates, and tracking running container versions. Build and deploy workflows without manual CLI tagging or registry configuration.