Prompt
How do I standardize local dev environments across a team?
Latest observation
To standardize local dev environments across a team, aim for “same setup, same tools, same versioning, same commands”—while keeping onboarding fast and minimizing “works on my machine” problems.
1) Choose one primary environment model
Pick one and make it the default for everyone:
- Containers: best for consistency
- Examples: Docker + Docker Compose, devcontainers (VS Code / GitHub Codespaces)
- Language/runtime version managers: good if you want lighter-weight setups
- Examples: nvm, asdf, pyenv, rbenv
- VM-based setups: strong isolation, heavier operationally
Most teams today standardize on containers + version managers.
2) Pin every version that matters
Lock down all runtime/tool versions:
- Node/Python/Java/Go/Ruby versions
- Package manager versions (
npm,pnpm,yarn,poetry,bundler, etc.) - Database and service versions
- CLI tools and linters/formatters
Use files like:
.nvmrc,.tool-versions(asdf),.python-versionpackage-lock.json,pnpm-lock.yaml,poetry.lock,Gemfile.lockdocker-compose.ymlwith explicit image tags, notlatest
3) Make setup reproducible with one command
Provide a single bootstrap path:
make setup./scripts/bootstraptask setup
That command should:
- install dependencies
- copy env files/templates
- start services
- run migrations/seed data
- verify prerequisites
Keep it idempotent so it can be re-run safely.
4) Containerize dependencies, not necessarily the whole app
A practical compromise:
- Run databases, caches, queues, and supporting services in Docker
- Run the app either:
- inside a container, or
- on the host using pinned local runtimes
This reduces environment drift a lot without making every edit cycle slow.
5) Use dev containers or Codespaces if you want maximum consistency
If your team uses VS Code or GitHub:
- devcontainer.json can define:
- OS image
- extensions
- forwarded ports
- post-create setup
- This gives near-identical environments across developers and CI.
6) Standardize configuration through templates
Create shared files for:
.env.example.editorconfig.gitignore- formatter/linter config
- pre-commit hooks
- shell setup instructions
Avoid manual copying; generate or template these if possible.
7) Align local dev with CI
Your local environment should mirror CI as closely as possible:
- same test commands
- same lint/format commands
- same build steps
- same dependency versions
- same environment variables
If CI and local diverge, developers will still hit surprises later.
8) Automate quality checks
Use hooks and CI to enforce standards:
- pre-commit hooks: format, lint, static checks
- CI: run tests and validation on every push/PR
- protect main branch from unverified changes
Tools:
husky,lefthook,pre-commit
9) Document only what’s necessary
Keep docs short and actionable:
- prerequisites
- first-run setup
- daily commands
- troubleshooting
A good README section is often enough if the scripts are solid.
10) Support onboarding and troubleshooting
Provide:
- a “new machine” checklist
- common fixes for port conflicts, stale volumes, lockfile issues
- a script to reset the environment:
make cleandocker compose down -v- reinstall dependencies
A simple recommended stack
For many teams, this works well:
- Docker Compose for DB/cache/services
- asdf or nvm/pyenv for local runtime versions
- Makefile or Taskfile for standard commands
- lockfiles for dependency pinning
- devcontainer optional for stronger consistency
- pre-commit / husky for local enforcement
Example standardized commands
Try to make these universal:
make setupmake devmake testmake lintmake formatmake reset
Common pitfalls
Avoid:
latesttags- undocumented manual steps
- relying on global installs
- inconsistent shell scripts across OSes
- too many “optional” setup paths
- letting everyone invent their own tooling
If you want, I can also give you:
- a recommended standardization blueprint,
- a sample repo structure, or
- a devcontainer + Docker Compose example.