Blank-canvas base Docker image for VS Code Dev Containers. One image, shared across all your Django projects.
Python 3.14.3 · uv · GitHub CLI · Node.js 24 LTS · Celery · Starship
docker pull alihaidar199527/django-devcontainer:latestEvery Django project needs the same developer tooling: Python, a package manager, a linter, a type checker, database clients, Redis tooling, Git, and a good terminal prompt. Configuring this from scratch on every machine wastes time and produces inconsistent environments.
This repository solves that problem with a single, shared base image. Push a change here and all your Django projects get the upgrade on the next docker pull — without touching any project code.
This repo has one job: build and publish the base development Docker image to Docker Hub.
It contains no Django files, no project-specific configuration, and no application code. Django itself, DRF, psycopg, redis-py, and any other project-level package are installed per project with uv add after the container starts.
This image is one half of a two-repo system.
| Repo | Responsibility |
|---|---|
django-devcontainer ← you are here |
Build and publish the base dev image |
django-template |
GitHub Template — the starting point for every new Django project |
When you open a Django project that uses this image, six containers start together via Docker Compose:
| Container | Port | Role |
|---|---|---|
app |
8000 | Django development server — your code runs here |
celery |
— | Celery worker, auto-restarts on code change via watchfiles |
celery-beat |
— | Periodic task scheduler |
postgres |
5432 | PostgreSQL 17 database |
redis |
6379 | Cache and Celery broker |
mailpit |
8025 / 1025 | Email catcher (SMTP on 1025, web UI on 8025) |
The app, celery, and celery-beat containers all pull this same image, which is why the Celery CLI and watchfiles are baked in.
All system build libraries are included (libpq, libssl, libjpeg, libxml2, and others), so packages like psycopg and Pillow compile without additional setup.
| Category | Tool | Purpose |
|---|---|---|
| Runtime | Python 3.14.3 (slim-bookworm) |
Language runtime — pinned to an exact version for reproducible builds |
| Package manager | uv | Ultra-fast Python package manager; replaces pip + venv |
| Version control | Git + GitHub CLI (gh) |
Source control and GitHub operations from the terminal |
| SSH | openssh-client | Enables git push via SSH from inside the container |
| JavaScript | Node.js 24 LTS | Required by Husky and commitlint git hooks in projects |
| Database | PostgreSQL 17 client | psql, pg_isready, pg_dump |
| Database | pgcli | Interactive PostgreSQL client with autocomplete and syntax highlighting |
| Cache / Queue | redis-cli | Test Redis cache and Celery broker from the terminal |
| Task queue | Celery | CLI baked in — worker and beat containers start without waiting for uv sync |
| Task queue | Flower | Celery monitoring web UI, accessible at :5555 |
| Task queue | watchfiles | Auto-reloads the Celery worker when source files change |
| Code quality | ruff | Linter and formatter — replaces flake8, isort, and black |
| Code quality | mypy | Static type checker |
| Code quality | pre-commit | Git hook manager |
| Shell | IPython | Rich interactive Python shell with autocomplete |
| API testing | HTTPie | Human-friendly HTTP client — http GET localhost:8000/api/ |
| Shell | Starship | Terminal prompt showing git branch, Python version, and git status |
These are intentionally absent. Install them per project with uv add:
Django → uv add django
djangorestframework → uv add djangorestframework
psycopg → uv add "psycopg[binary,pool]"
redis-py → uv add redis
Celery app config → defined in your project's config/celery.py
django-devcontainer/
├── .github/
│ ├── dependabot.yml # Weekly auto-updates for Actions + Docker base image
│ ├── labels.yml # Label definitions — name, color, description
│ └── workflows/
│ ├── docker.yml # Builds + pushes image on push/PR to main
│ ├── dockerhub-description.yml # Syncs README.md to Docker Hub on push to main
│ └── labels.yml # Syncs labels.yml to GitHub labels
├── docker/
│ └── Dockerfile.dev # The image recipe
├── scripts/
│ └── shell_setup.sh # Shell aliases and Starship prompt
├── .dockerignore # Excludes unnecessary files from the build context
├── .gitignore # Ensures .env files are never committed
└── README.md # This file — also synced to Docker Hub
Five files under .github/ handle everything automatically.
| File | Trigger | What happens |
|---|---|---|
workflows/docker.yml |
Push to main (docker/, scripts/ changed) |
Builds + pushes :latest + :sha-xxx to Docker Hub |
workflows/docker.yml |
PR targeting main (same path filter) |
Builds only — validates Dockerfile, never pushes |
workflows/docker.yml |
Manual dispatch | Builds + pushes, with force-rebuild and push toggle |
workflows/dockerhub-description.yml |
Push to main (README.md changed) |
Updates Docker Hub description |
workflows/dockerhub-description.yml |
PR targeting main (README.md changed) |
Runs but skips update until merged |
workflows/dockerhub-description.yml |
Manual dispatch | Forces immediate Docker Hub sync |
workflows/labels.yml |
Push to main (.github/labels.yml changed) |
Syncs all labels to GitHub |
workflows/labels.yml |
Manual dispatch | Bootstrap all labels in one go |
dependabot.yml |
Every Monday 09:00 UTC | Scans Actions + Docker, opens PRs against develop |
dependabot.yml |
Manual via Insights → Dependency graph | Immediate on-demand scan |
labels.yml |
— | Data file only — no trigger of its own |
Builds the multi-platform Docker image (linux/amd64 + linux/arm64) and pushes it to Docker Hub. Path-filtered so a README change never triggers an unnecessary image rebuild. PR builds compile the image to validate the Dockerfile without pushing — only merged pushes publish to Docker Hub.
Syncs README.md to the Docker Hub repository description page. Runs on every README.md change merged to main. PRs trigger the workflow so GitHub can show a check, but the actual Docker Hub update is skipped until the merge is complete.
Keeps GitHub repository labels in sync with .github/labels.yml. Labels are version-controlled — add or rename a label in the file, push, and GitHub reflects the change automatically. Supports manual dispatch for first-time bootstrapping.
Automatically monitors two ecosystems and opens PRs against develop when updates are found — all GitHub Actions versions used in workflows, and the Docker base image in Dockerfile.dev. Runs every Monday at 09:00 UTC. Can also be triggered manually from Insights → Dependency graph → Dependabot.
The single source of truth for all repository labels. Defines each label's name, hex color, and description. Read by workflows/labels.yml — has no trigger of its own.
Push to main (Dockerfile or scripts changed)
→ GitHub Actions detects the change
→ Builds linux/amd64 + linux/arm64 in parallel
→ Pushes :latest and :sha-<commit> to Docker Hub
→ Job summary written to Actions log
PR targeting main (Dockerfile or scripts changed)
→ GitHub Actions detects the change
→ Builds linux/amd64 + linux/arm64 to validate
→ Does NOT push — PR check goes green or red
→ Merge when green
The first build takes 20–30 minutes (no cache). All subsequent builds complete in 3–5 minutes thanks to GitHub Actions layer caching.
| Platform | Architecture |
|---|---|
| Windows · Linux · GCP | linux/amd64 |
| Apple Silicon Mac | linux/arm64 |
Docker pulls the correct platform automatically.
| Tag | Published when |
|---|---|
latest |
Every push to main |
sha-xxxxxxx |
Every build — pin to this for rollback |
All aliases are defined in scripts/shell_setup.sh and baked into the image.
| Alias | Expands to |
|---|---|
pm |
python manage.py |
pmr |
python manage.py runserver 0.0.0.0:8000 |
pmm |
python manage.py migrate |
pmmk |
python manage.py makemigrations |
pms |
python manage.py shell_plus |
pmsu |
python manage.py createsuperuser |
pmcs |
python manage.py collectstatic --noinput |
pmt |
python manage.py test |
| Alias | Expands to |
|---|---|
cw |
celery -A config worker -l INFO --pool=solo |
cb |
celery -A config beat -l INFO --scheduler django_celery_beat.schedulers:DatabaseScheduler |
cf |
celery -A config flower --port=5555 |
cpurge |
celery -A config purge |
| Alias | Expands to | Notes |
|---|---|---|
uvs |
uv sync |
Sync venv from pyproject.toml — use after cloning or pulling |
uva |
uv add |
Add a package and update pyproject.toml + lockfile |
uvr |
uv remove |
Remove a package and update pyproject.toml + lockfile |
uvl |
uv pip list |
List installed packages |
uvf |
uv pip freeze |
Freeze installed packages |
| Alias | Expands to |
|---|---|
gs |
git status |
ga |
git add |
gc |
git commit -m |
gp |
git push |
gl |
git log --oneline --graph --decorate |
gco |
git checkout |
gb |
git branch |
| Alias | Expands to |
|---|---|
ll |
ls -alFh --color=auto |
la |
ls -A --color=auto |
cls |
clear |
dps |
docker ps |
dlogs |
docker logs |
Edit ARG PYTHON_VERSION in docker/Dockerfile.dev — the single source of truth. Verify the tag exists at hub.docker.com/_/python/tags first.
ARG PYTHON_VERSION=3.15.0Commit, push to a branch, open a PR against main. The PR build validates the new Python version compiles correctly. Merge when green — image publishes automatically.
RUN apt-get update && apt-get install -y --no-install-recommends \
your-new-tool \ # reason for including
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*RUN uv pip install --system \
ruff mypy pre-commit ipython \
pgcli httpie celery flower watchfiles \
your-new-packageSymptom: denied: requested access to the resource is denied
- Go to Settings → Secrets and variables → Actions
- Confirm both
DOCKERHUB_USERNAMEandDOCKERHUB_TOKENare present - If expired: Docker Hub → Account Settings → Personal access tokens → delete → create new → update secret
- Re-run from the Actions tab
Symptom: manifest unknown for python:3.x.x-slim-bookworm
Check hub.docker.com/_/python/tags and update ARG PYTHON_VERSION to an existing tag.
ssh-add -l # check loaded keys
ssh-add "%USERPROFILE%\.ssh\id_ed25519" # Windows — load key
ssh-add ~/.ssh/id_ed25519 # macOS / Linux
ssh -T git@github.com # verify auth
git remote set-url origin git@github.com:YOUR_USERNAME/django-devcontainer.git # fix HTTPS remoteOn Windows after restart:
sc config ssh-agent start= auto
net start ssh-agent- Wait for the taskbar whale icon to stop animating
- Right-click whale → Restart Docker Desktop
- Task Manager → end all
Docker Desktopprocesses → reopen
Python 3.14.3 · Node.js 24 LTS · Debian 12 Bookworm · 2026