Skip to content

Dev Container

Pain point

Development directly on Windows, macOS, and Linux produces different paths, shells, native packages, line endings, and tool behavior. Each environment can be configured successfully, but maintaining equivalent setup across every machine consumes time and makes failures harder to reproduce.

This template uses a Linux Dev Container as its reference development environment. Contributors may use different host operating systems, but the project runs inside the same defined environment when platform behavior matters.

Selected design

File Responsibility Why it is separate
.devcontainer/Dockerfile Define the operating system, native packages, and bootstrap binaries Image-level requirements can be cached and rebuilt consistently
.devcontainer/devcontainer.json Tell compatible editors how to build and enter the environment Editor integration remains declarative and easy to inspect
scripts/setup.sh Initialize the mounted repository after creation Repository-dependent setup cannot run before the workspace is available
mise.toml Install project tools and expose shared commands Tool choices remain visible and usable outside the image where supported

The Dockerfile uses Microsoft's Ubuntu Dev Container base and runs as its provided development user. It installs Python and tmux as operating-system packages, then copies Mise and uv from their published container images.

Python supports Python-based hook environments and repository utilities, while uvx runs tools such as Zensical in isolated environments. Its presence does not make the eventual application a Python project. Mise, uv, and their source images intentionally track current releases; the template prefers a current development baseline over byte-for-byte historical rebuilds.

Creation lifecycle

Host opens repository
→ Dev Container builds the Dockerfile
→ workspace is mounted
→ postCreateCommand runs scripts/setup.sh
→ setup trusts mise.toml and installs locked tools
→ Mise project-entry automation configures local Git tooling
→ workspace is ready

devcontainer.json forwards the optional MISE_GITHUB_TOKEN from the host. Mise can use it for authenticated GitHub downloads and avoid anonymous API rate limits. The token is optional and must never be committed.

Rebuild the container when the Dockerfile or devcontainer.json changes. Run mise install when only project tools change; rebuilding the complete image would add time without changing the image itself.

What consistency it provides

  • One Linux reference for shells, paths, native packages, and executable behavior.
  • A version-controlled machine definition instead of personal setup notes.
  • The same onboarding path on supported Windows, macOS, and Linux hosts.
  • A clear boundary between operating-system packages and project tools.

The container does not make host behavior identical. Docker, filesystem performance, networking, credentials, and hardware still originate outside it. Native development remains possible, but disagreements are resolved against the container because it is the documented reference.

Verify and adapt

After opening the container, verify the environment with:

mise doctor
mise ls --current
prek run --all-files

Add an operating-system package to the Dockerfile only when it is required before project tools can operate. Add runtimes, linters, and recurring project commands through Mise. Keep post-create work idempotent and limited to repository initialization.

Official documentation