Menu

Topic 6 of 8

Local Dev Environments Basics

Learn Local Dev Environments Basics for free with explanations, exercises, and a quick test (for Platform Engineer).

Published: January 23, 2026 | Updated: January 23, 2026

Why this matters

As a Platform Engineer, you enable developers to start coding fast with minimal friction. Solid local environments reduce onboarding time, prevent “works on my machine” bugs, and shorten feedback loops. You will:

  • Provide one-command setup for new contributors.
  • Spin up services (API, DB, cache, queues) consistently across machines.
  • Mirror production behavior safely without requiring cloud access.
  • Bake in fast feedback: hot reloads, health checks, realistic seed data.

Concept explained simply

A local dev environment is a lightweight replica of your app’s runtime on a laptop. It should be reproducible (anyone can get the same result), isolated (doesn’t break your system), and fast (short feedback loop).

Mental model

Think of it as a portable lab bench: each service is a labeled beaker (API, DB, cache). Docker Compose is your tray that keeps them together. A Makefile or script is your instruction card: one command sets everything up the same way every time.

Core components of a good local environment

  • Runtime: language/toolchain versions (e.g., Node, Python, Go).
  • Dependencies: package managers and lockfiles.
  • Services: DB (Postgres), cache (Redis), message broker, etc.
  • Configuration: .env files with safe defaults; secrets kept out of VCS.
  • Data: migrations + seed scripts for realistic test data.
  • Tooling: Makefile or scripts for one-command setup, test, lint, run.
  • Reproducibility: containers/devcontainers; documented, idempotent steps.

Worked examples

Example 1: API + Postgres + Redis via Docker Compose

Goal: run an API locally with database and cache, using service names for networking.

version: "3.9"
services:
  api:
    build: .
    command: uvicorn app:app --host 0.0.0.0 --port 8000
    environment:
      - DATABASE_URL=postgresql://postgres:postgres@db:5432/app
      - REDIS_URL=redis://cache:6379/0
    ports:
      - "8000:8000"
    depends_on:
      - db
      - cache
  db:
    image: postgres:15
    environment:
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: app
    ports:
      - "5432:5432"
    volumes:
      - db_data:/var/lib/postgresql/data
  cache:
    image: redis:7
    ports:
      - "6379:6379"
volumes:
  db_data:

Why it works: Compose creates a shared network where service names (db, cache) resolve automatically. Ports expose the API to your browser. Data persists in a named volume.

Example 2: Dev Containers for consistent toolchains

Goal: ensure every developer uses the same OS packages and language versions, even on different host systems.

// .devcontainer/devcontainer.json
{
  "name": "app-dev",
  "build": {
    "dockerfile": "Dockerfile"
  },
  "forwardPorts": [8000, 5432, 6379],
  "postCreateCommand": "make setup",
  "remoteUser": "vscode"
}

Why it works: the editor attaches into a container with a fixed image and tools; onboarding is reduced to “Open in Dev Container” and run the standard commands.

Example 3: One-command onboarding with Makefile

# Makefile
SHELL := /bin/bash

.PHONY: setup run stop logs test

setup:
	@if [ ! -f .env ]; then cp .env.example .env; fi
	docker compose pull || true
	docker compose build --pull
	docker compose up -d
	# Run migrations and seed data inside the api container
	docker compose exec -T api sh -lc "alembic upgrade head || true; python seed.py || true"

run:
	docker compose up -d

stop:
	docker compose down

logs:
	docker compose logs -f --tail=100

test:
	docker compose exec -T api pytest -q

Why it works: idempotent steps mean running make setup twice won’t break anything; it only ensures the right state.

Example 4: Health checks and data seeding

Expose a simple health endpoint and seed minimal data so devs can verify the stack.

# health.py (pseudo)
@app.get("/health")
def health():
    return {"status": "ok"}

# seed.py (pseudo)
print("Seeding sample users...")
# insert minimal seed rows here

Verification flow: start stack, call /health, log in with seeded credentials, run one request end-to-end.

Step-by-step: set up a minimal local environment

  1. Define services in docker-compose.yml (API, DB, cache).
  2. Create .env.example with safe defaults; document required variables.
  3. Add Makefile targets: setup, run, stop, logs, test.
  4. Implement migrations + seed scripts.
  5. Add a health endpoint and document the ready check.
  6. Test on a clean machine or container; refine until setup is reliable.

Exercises

Do these hands-on tasks. Use the checklist to self-verify.

Exercise ex1: Compose a 3-service stack

Goal: API + Postgres + Redis run locally, with a working health check.

  • A docker-compose.yml with api, db, cache services.
  • api depends_on db and cache, exposes port 8000.
  • DATABASE_URL and REDIS_URL use service names (db, cache).
  • Verify by calling the /health endpoint.

Exercise ex2: One-command onboarding

Goal: A single command sets up, migrates, seeds, and starts logs.

  • Create Makefile targets: setup, run, stop, logs.
  • setup should create .env if missing, build images, start services, run migrations, seed data.
  • Verify setup is idempotent: running twice should not fail.

Common mistakes and self-check

  • Hardcoding localhost in service URLs. Self-check: Use service names in Compose (db, cache) inside containers.
  • Committing secrets. Self-check: Only commit .env.example; keep .env in .gitignore.
  • No seed data. Self-check: Can a new dev click through the app in 2 minutes?
  • Non-idempotent setup. Self-check: Run the setup command twice; it should succeed both times.
  • Missing health checks. Self-check: Is there a documented endpoint and command to verify readiness?
  • Slow rebuilds. Self-check: Are language dependencies cached with proper Docker layer ordering?

Practical projects

  • Starter kit: Template repo with Compose, Makefile, .env.example, health check, migrations, seed, and README.
  • Devcontainerized monorepo: Multiple services each with consistent devcontainer setup and shared Makefile targets.
  • DX metrics prototype: Script that times setup, boot, test run; report median times for continuous improvement.

Who this is for

  • Platform Engineers creating reliable, fast developer workflows.
  • Backend Engineers who want reproducible, testable local stacks.
  • New joiners who need a clear, one-command setup.

Prerequisites

  • Basic Docker and Docker Compose usage.
  • Comfort with a scripting language (Shell, Make, or similar).
  • Familiarity with your stack’s package manager and migrations.

Learning path

  • Day 1: Recreate the 3-service Compose example; add health check.
  • Day 2: Add Makefile onboarding; make setup idempotent.
  • Day 3: Add devcontainer; time setup and boot; improve caching.
  • Day 4+: Add tests and lint targets; standardize logs and diagnostics.

Mini challenge

Constraint: You cannot install Postgres locally on the host. Deliver an API that starts in under 5 seconds after containers are up, with a single make setup. Include a health check and at least two seeded entities. Measure and note the total time from clean clone to first successful /health response.

Next steps

  • Add pre-commit hooks to enforce formatting and linting locally.
  • Introduce ephemeral preview environments in CI for parity checks.
  • Collect feedback from new joiners; iterate on docs and scripts.

Quick Test

Take the quick test below to check your understanding. Available to everyone; only logged-in users get saved progress.

Practice Exercises

2 exercises to complete

Instructions

Create docker-compose.yml with api, db (Postgres), and cache (Redis). The api should expose port 8000 and depend on db and cache. Inside api, use DATABASE_URL=postgresql://postgres:postgres@db:5432/app and REDIS_URL=redis://cache:6379/0. Start the stack and verify /health returns ok.

  1. Write docker-compose.yml as described.
  2. Run: docker compose up -d
  3. Check: docker compose ps
  4. Verify: curl http://localhost:8000/health
Expected Output
docker compose ps shows api, db, cache healthy; curl to /health returns {"status":"ok"}.

Local Dev Environments Basics — Quick Test

Test your knowledge with 8 questions. Pass with 70% or higher.

8 questions70% to pass

Have questions about Local Dev Environments Basics?

AI Assistant

Ask questions about this tool