Skip to content

Debug Configurations

This template provides production-ready VS Code launch.json debug configurations covering Python, TypeScript/Node.js, Go, Bash, PowerShell, Docker containers, remote debugging, and multi-target setups.

Quick Start

# Copy launch.json to your project
cp coding-style-guide/.vscode/launch.json your-project/.vscode/

# Or copy the entire .vscode directory
cp -r coding-style-guide/.vscode your-project/

File Structure

your-project/
├── .vscode/
│   ├── launch.json          # Debug configurations (this template)
│   ├── settings.json        # Editor and formatter settings
│   ├── extensions.json      # Recommended extensions
│   └── tasks.json           # Pre/post-launch tasks (optional)
└── ...

Configuration Overview

Category Configurations Debug Port
Python: General Current File, Module N/A
Python: Web Frameworks FastAPI, Django, Flask N/A
Python: Testing pytest (File), pytest (All) N/A
Python: Attach Attach localhost 5678
Node.js: Launch Current File, ts-node, Express/NestJS, npm start N/A
Node.js: Testing Jest, Vitest N/A
Node.js: Attach Attach localhost 9229
Go: Launch Current File, Package, Test N/A
Go: Attach Attach localhost (Delve) 2345
Bash Current File N/A
PowerShell Current File, Interactive N/A
Docker Python, Node, Go Attach 5678, 9229, 2345
Remote: SSH Python, Node via tunnel 5678, 9229
Remote: Kubernetes Python, Node, Go via port-forward 5678, 9229, 2345
Multi-target Full Stack combos, Docker combos Multiple

Python Debug Configurations

Python Current File

{
  "name": "Python: Current File",
  "type": "debugpy",
  "request": "launch",
  "program": "${file}",
  "console": "integratedTerminal",
  "justMyCode": true,
  "env": {
    "PYTHONDONTWRITEBYTECODE": "1"
  }
}

Step Into Library Code

{
  "name": "Python: Current File (All Code)",
  "type": "debugpy",
  "request": "launch",
  "program": "${file}",
  "console": "integratedTerminal",
  "justMyCode": false
}

Run a Module

{
  "name": "Python: Module",
  "type": "debugpy",
  "request": "launch",
  "module": "${input:pythonModule}",
  "console": "integratedTerminal",
  "justMyCode": true
}

FastAPI

{
  "name": "Python: FastAPI",
  "type": "debugpy",
  "request": "launch",
  "module": "uvicorn",
  "args": ["app.main:app", "--reload", "--port", "8000"],
  "console": "integratedTerminal",
  "justMyCode": true,
  "jinja": true,
  "env": {
    "ENVIRONMENT": "development"
  }
}

Django

{
  "name": "Python: Django",
  "type": "debugpy",
  "request": "launch",
  "program": "${workspaceFolder}/manage.py",
  "args": ["runserver", "--noreload"],
  "django": true,
  "justMyCode": true,
  "env": {
    "DJANGO_SETTINGS_MODULE": "config.settings.local"
  }
}

Flask

{
  "name": "Python: Flask",
  "type": "debugpy",
  "request": "launch",
  "module": "flask",
  "args": ["run", "--debug", "--port", "5000"],
  "jinja": true,
  "justMyCode": true,
  "env": {
    "FLASK_APP": "app:create_app",
    "FLASK_ENV": "development"
  }
}

pytest (Current File)

{
  "name": "Python: pytest",
  "type": "debugpy",
  "request": "launch",
  "module": "pytest",
  "args": ["-xvs", "${file}"],
  "console": "integratedTerminal",
  "justMyCode": false
}

pytest (All Tests)

{
  "name": "Python: pytest (All Tests)",
  "type": "debugpy",
  "request": "launch",
  "module": "pytest",
  "args": ["-xvs", "tests/"],
  "console": "integratedTerminal",
  "justMyCode": false
}

Python Attach to Running Process

{
  "name": "Python: Attach (localhost:5678)",
  "type": "debugpy",
  "request": "attach",
  "connect": {
    "host": "localhost",
    "port": 5678
  },
  "pathMappings": [
    {
      "localRoot": "${workspaceFolder}",
      "remoteRoot": "/app"
    }
  ],
  "justMyCode": true
}

Prepare the target process with:

# Add to your application entrypoint
import debugpy

debugpy.listen(("0.0.0.0", 5678))
print("Waiting for debugger attach...")
debugpy.wait_for_client()

TypeScript / Node.js Debug Configurations

Node Current File

{
  "name": "Node: Current File",
  "type": "node",
  "request": "launch",
  "program": "${file}",
  "console": "integratedTerminal",
  "skipFiles": ["<node_internals>/**"]
}

TypeScript with ts-node

{
  "name": "Node: ts-node",
  "type": "node",
  "request": "launch",
  "runtimeExecutable": "npx",
  "runtimeArgs": ["ts-node"],
  "args": ["${file}"],
  "console": "integratedTerminal",
  "skipFiles": ["<node_internals>/**"],
  "resolveSourceMapLocations": [
    "${workspaceFolder}/**",
    "!**/node_modules/**"
  ]
}

Express / NestJS Server

{
  "name": "Node: Express/NestJS",
  "type": "node",
  "request": "launch",
  "runtimeExecutable": "npx",
  "runtimeArgs": ["ts-node"],
  "args": ["${workspaceFolder}/src/main.ts"],
  "console": "integratedTerminal",
  "skipFiles": ["<node_internals>/**"],
  "env": {
    "NODE_ENV": "development"
  },
  "resolveSourceMapLocations": [
    "${workspaceFolder}/**",
    "!**/node_modules/**"
  ]
}

npm start

{
  "name": "Node: npm start",
  "type": "node",
  "request": "launch",
  "runtimeExecutable": "npm",
  "runtimeArgs": ["start"],
  "console": "integratedTerminal",
  "skipFiles": ["<node_internals>/**"]
}

Jest (Current File)

{
  "name": "Node: Jest Current File",
  "type": "node",
  "request": "launch",
  "runtimeExecutable": "npx",
  "runtimeArgs": [
    "jest",
    "--runInBand",
    "--no-cache",
    "${relativeFile}"
  ],
  "console": "integratedTerminal",
  "skipFiles": ["<node_internals>/**"]
}

Vitest (Current File)

{
  "name": "Node: Vitest Current File",
  "type": "node",
  "request": "launch",
  "runtimeExecutable": "npx",
  "runtimeArgs": [
    "vitest",
    "run",
    "--reporter=verbose",
    "${relativeFile}"
  ],
  "console": "integratedTerminal",
  "skipFiles": ["<node_internals>/**"]
}

Node Attach to Running Process

{
  "name": "Node: Attach (localhost:9229)",
  "type": "node",
  "request": "attach",
  "port": 9229,
  "restart": true,
  "skipFiles": ["<node_internals>/**"],
  "localRoot": "${workspaceFolder}",
  "remoteRoot": "/app"
}

Start the target process with the --inspect flag:

# Standard Node.js
node --inspect=0.0.0.0:9229 dist/main.js

# ts-node
npx ts-node --inspect=0.0.0.0:9229 src/main.ts

# npm script (add to package.json)
# "scripts": { "debug": "node --inspect=0.0.0.0:9229 dist/main.js" }
npm run debug

Go Debug Configurations

Go Current File

{
  "name": "Go: Current File",
  "type": "go",
  "request": "launch",
  "mode": "debug",
  "program": "${file}",
  "env": {},
  "args": []
}

Package

{
  "name": "Go: Package",
  "type": "go",
  "request": "launch",
  "mode": "debug",
  "program": "${workspaceFolder}",
  "env": {},
  "args": []
}

Test Current File

{
  "name": "Go: Test Current File",
  "type": "go",
  "request": "launch",
  "mode": "test",
  "program": "${file}",
  "args": ["-v"]
}

Attach via Delve

{
  "name": "Go: Attach (localhost:2345)",
  "type": "go",
  "request": "attach",
  "mode": "remote",
  "port": 2345,
  "host": "localhost",
  "substitutePath": [
    {
      "from": "${workspaceFolder}",
      "to": "/app"
    }
  ]
}

Start the target process with Delve:

# Headless Delve server
dlv debug --headless --listen=:2345 --api-version=2 --accept-multiclient ./cmd/server

# Attach to running PID
dlv attach --headless --listen=:2345 --api-version=2 --accept-multiclient <PID>

# Run tests with Delve
dlv test --headless --listen=:2345 --api-version=2 --accept-multiclient ./pkg/...

Bash Debug Configuration

{
  "name": "Bash: Current File",
  "type": "bashdb",
  "request": "launch",
  "program": "${file}",
  "args": [],
  "cwd": "${workspaceFolder}",
  "terminalKind": "integrated"
}

Required extension: rogalmic.bash-debug

PowerShell Debug Configurations

PowerShell Current File

{
  "name": "PowerShell: Current File",
  "type": "PowerShell",
  "request": "launch",
  "script": "${file}",
  "cwd": "${workspaceFolder}"
}

Interactive Session

{
  "name": "PowerShell: Interactive",
  "type": "PowerShell",
  "request": "launch",
  "script": "",
  "createTemporaryIntegratedConsole": true
}

Docker Container Debugging

Python Container

Add debugpy to your container and expose port 5678:

# Dockerfile (debug variant)
FROM python:3.13-slim

WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt debugpy

COPY . .

# Expose app port and debug port
EXPOSE 8000 5678

CMD ["python", "-m", "debugpy", "--listen", "0.0.0.0:5678", \
     "-m", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
# docker-compose.debug.yml
services:
  api:
    build:
      context: .
      dockerfile: Dockerfile.debug
    ports:
      - "8000:8000"
      - "5678:5678"
    volumes:
      - .:/app
    environment:
      - ENVIRONMENT=development
{
  "name": "Docker: Python Attach",
  "type": "debugpy",
  "request": "attach",
  "connect": {
    "host": "localhost",
    "port": 5678
  },
  "pathMappings": [
    {
      "localRoot": "${workspaceFolder}",
      "remoteRoot": "/app"
    }
  ],
  "justMyCode": true
}

Node.js Container

# Dockerfile (debug variant)
FROM node:22-alpine

WORKDIR /app
COPY package*.json ./
RUN npm ci

COPY . .

EXPOSE 3000 9229

CMD ["node", "--inspect=0.0.0.0:9229", "dist/main.js"]
# docker-compose.debug.yml
services:
  frontend:
    build:
      context: .
      dockerfile: Dockerfile.debug
    ports:
      - "3000:3000"
      - "9229:9229"
    volumes:
      - .:/app
      - /app/node_modules
    environment:
      - NODE_ENV=development
{
  "name": "Docker: Node Attach",
  "type": "node",
  "request": "attach",
  "port": 9229,
  "restart": true,
  "localRoot": "${workspaceFolder}",
  "remoteRoot": "/app",
  "skipFiles": ["<node_internals>/**"]
}

Go Container

# Dockerfile (debug variant)
FROM golang:1.24-alpine

RUN go install github.com/go-delve/delve/cmd/dlv@latest

WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download

COPY . .
RUN go build -gcflags="all=-N -l" -o /server ./cmd/server

EXPOSE 8080 2345

CMD ["dlv", "exec", "/server", "--headless", "--listen=:2345", \
     "--api-version=2", "--accept-multiclient"]
# docker-compose.debug.yml
services:
  backend:
    build:
      context: .
      dockerfile: Dockerfile.debug
    ports:
      - "8080:8080"
      - "2345:2345"
    security_opt:
      - "seccomp:unconfined"
    cap_add:
      - SYS_PTRACE
    volumes:
      - .:/app
{
  "name": "Docker: Go Attach (Delve)",
  "type": "go",
  "request": "attach",
  "mode": "remote",
  "port": 2345,
  "host": "localhost",
  "substitutePath": [
    {
      "from": "${workspaceFolder}",
      "to": "/app"
    }
  ]
}

Remote Debugging

SSH Tunnel

Set up an SSH tunnel to forward the debug port from a remote host:

# Python remote debugging (port 5678)
ssh -L 5678:localhost:5678 user@remote-host

# Node.js remote debugging (port 9229)
ssh -L 9229:localhost:9229 user@remote-host

# Go remote debugging (port 2345)
ssh -L 2345:localhost:2345 user@remote-host

# Multiple ports in one tunnel
ssh -L 5678:localhost:5678 -L 9229:localhost:9229 user@remote-host
{
  "name": "Remote: Python via SSH Tunnel",
  "type": "debugpy",
  "request": "attach",
  "connect": {
    "host": "localhost",
    "port": 5678
  },
  "pathMappings": [
    {
      "localRoot": "${workspaceFolder}",
      "remoteRoot": "/home/user/app"
    }
  ],
  "justMyCode": true
}
{
  "name": "Remote: Node via SSH Tunnel",
  "type": "node",
  "request": "attach",
  "port": 9229,
  "localRoot": "${workspaceFolder}",
  "remoteRoot": "/home/user/app",
  "skipFiles": ["<node_internals>/**"]
}

Kubernetes Port-Forward

Forward debug ports from a Kubernetes pod to your local machine:

# Python debug port
kubectl port-forward deployment/api-server 5678:5678

# Node.js debug port
kubectl port-forward deployment/web-frontend 9229:9229

# Go debug port
kubectl port-forward deployment/backend 2345:2345

# Multiple pods (run in separate terminals)
kubectl port-forward pod/api-abc123 5678:5678 &
kubectl port-forward pod/web-xyz789 9229:9229 &
{
  "name": "K8s: Python Attach (port-forward)",
  "type": "debugpy",
  "request": "attach",
  "connect": {
    "host": "localhost",
    "port": 5678
  },
  "pathMappings": [
    {
      "localRoot": "${workspaceFolder}",
      "remoteRoot": "/app"
    }
  ],
  "justMyCode": true,
  "preLaunchTask": "k8s-port-forward-python"
}
{
  "name": "K8s: Node Attach (port-forward)",
  "type": "node",
  "request": "attach",
  "port": 9229,
  "localRoot": "${workspaceFolder}",
  "remoteRoot": "/app",
  "skipFiles": ["<node_internals>/**"],
  "preLaunchTask": "k8s-port-forward-node"
}
{
  "name": "K8s: Go Attach (port-forward)",
  "type": "go",
  "request": "attach",
  "mode": "remote",
  "port": 2345,
  "host": "localhost",
  "substitutePath": [
    {
      "from": "${workspaceFolder}",
      "to": "/app"
    }
  ],
  "preLaunchTask": "k8s-port-forward-go"
}

Tasks for Kubernetes Port-Forward

Create .vscode/tasks.json to automate port-forwarding as a pre-launch step:

{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "k8s-port-forward-python",
      "type": "shell",
      "command": "kubectl",
      "args": ["port-forward", "deployment/api-server", "5678:5678"],
      "isBackground": true,
      "problemMatcher": {
        "pattern": { "regexp": "^$" },
        "background": {
          "activeOnStart": true,
          "beginsPattern": "^Forwarding",
          "endsPattern": "^Forwarding"
        }
      }
    },
    {
      "label": "k8s-port-forward-node",
      "type": "shell",
      "command": "kubectl",
      "args": ["port-forward", "deployment/web-frontend", "9229:9229"],
      "isBackground": true,
      "problemMatcher": {
        "pattern": { "regexp": "^$" },
        "background": {
          "activeOnStart": true,
          "beginsPattern": "^Forwarding",
          "endsPattern": "^Forwarding"
        }
      }
    },
    {
      "label": "k8s-port-forward-go",
      "type": "shell",
      "command": "kubectl",
      "args": ["port-forward", "deployment/backend", "2345:2345"],
      "isBackground": true,
      "problemMatcher": {
        "pattern": { "regexp": "^$" },
        "background": {
          "activeOnStart": true,
          "beginsPattern": "^Forwarding",
          "endsPattern": "^Forwarding"
        }
      }
    },
    {
      "label": "npm-install",
      "type": "shell",
      "command": "npm",
      "args": ["install"],
      "options": { "cwd": "${workspaceFolder}" }
    }
  ]
}

Multi-Target (Compound) Debugging

Compound configurations launch multiple debug sessions simultaneously.

Full Stack: Python API + Node Frontend

{
  "compounds": [
    {
      "name": "Full Stack: Python API + Node Frontend",
      "configurations": [
        "Python: FastAPI",
        "Node: npm start"
      ],
      "stopAll": true,
      "preLaunchTask": "npm-install"
    }
  ]
}

Full Stack: Django + Node Frontend

{
  "compounds": [
    {
      "name": "Full Stack: Django + Node Frontend",
      "configurations": [
        "Python: Django",
        "Node: npm start"
      ],
      "stopAll": true
    }
  ]
}

Docker: Python + Node Attach

{
  "compounds": [
    {
      "name": "Docker: Python + Node Attach",
      "configurations": [
        "Docker: Python Attach",
        "Docker: Node Attach"
      ],
      "stopAll": true
    }
  ]
}

Launch vs Attach

Aspect Launch Attach
Process control VS Code starts the process Process already running
Use case Local development Containers, remote, running servers
request value "launch" "attach"
Path mapping Automatic Requires pathMappings / substitutePath
Restart behavior Restarts automatically Manual or "restart": true
Environment variables Set via env Set in the running process

When to Use Launch

{
  "name": "Python: FastAPI",
  "type": "debugpy",
  "request": "launch",
  "module": "uvicorn",
  "args": ["app.main:app", "--reload"]
}
{
  "name": "Node: Express",
  "type": "node",
  "request": "launch",
  "runtimeExecutable": "npx",
  "runtimeArgs": ["ts-node"],
  "args": ["src/main.ts"]
}
{
  "name": "Go: Current File",
  "type": "go",
  "request": "launch",
  "mode": "debug",
  "program": "${file}"
}

When to Use Attach

{
  "name": "Docker: Python Attach",
  "type": "debugpy",
  "request": "attach",
  "connect": { "host": "localhost", "port": 5678 },
  "pathMappings": [
    { "localRoot": "${workspaceFolder}", "remoteRoot": "/app" }
  ]
}
{
  "name": "Docker: Node Attach",
  "type": "node",
  "request": "attach",
  "port": 9229,
  "localRoot": "${workspaceFolder}",
  "remoteRoot": "/app"
}
{
  "name": "Docker: Go Attach",
  "type": "go",
  "request": "attach",
  "mode": "remote",
  "port": 2345,
  "substitutePath": [
    { "from": "${workspaceFolder}", "to": "/app" }
  ]
}

Input Variables

Use inputs to prompt for values at debug launch time:

{
  "inputs": [
    {
      "id": "pythonModule",
      "description": "Python module to run (e.g., mypackage.cli)",
      "type": "promptString",
      "default": "mypackage.cli"
    },
    {
      "id": "debugPort",
      "description": "Debug port number",
      "type": "promptString",
      "default": "5678"
    },
    {
      "id": "k8sNamespace",
      "description": "Kubernetes namespace",
      "type": "pickString",
      "options": ["default", "development", "staging"],
      "default": "default"
    }
  ]
}

Reference inputs in configurations with ${input:variableId}:

{
  "name": "Python: Module (prompted)",
  "type": "debugpy",
  "request": "launch",
  "module": "${input:pythonModule}",
  "console": "integratedTerminal"
}
{
  "name": "Python: Attach (prompted port)",
  "type": "debugpy",
  "request": "attach",
  "connect": {
    "host": "localhost",
    "port": "${input:debugPort}"
  }
}

Required Extensions

Language Extension Extension ID
Python Python Debugger ms-python.debugpy
Node.js Built-in (included with VS Code)
Go Go golang.go
Bash Bash Debug rogalmic.bash-debug
PowerShell PowerShell ms-vscode.powershell
Docker Docker ms-azuretools.vscode-docker
Kubernetes Kubernetes ms-kubernetes-tools.vscode-kubernetes-tools
# Install all debugging extensions
code --install-extension ms-python.debugpy
code --install-extension golang.go
code --install-extension rogalmic.bash-debug
code --install-extension ms-vscode.powershell
code --install-extension ms-azuretools.vscode-docker
code --install-extension ms-kubernetes-tools.vscode-kubernetes-tools

Customization Guide

Adding a New Configuration

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Your Custom Config",
      "type": "debugpy",
      "request": "launch",
      "program": "${workspaceFolder}/src/main.py",
      "args": ["--verbose"],
      "env": {
        "DATABASE_URL": "postgresql://localhost:5432/devdb",
        "LOG_LEVEL": "DEBUG"
      },
      "console": "integratedTerminal",
      "justMyCode": true
    }
  ]
}

Environment-Specific Configurations

{
  "name": "Python: FastAPI (staging)",
  "type": "debugpy",
  "request": "launch",
  "module": "uvicorn",
  "args": ["app.main:app", "--port", "8000"],
  "envFile": "${workspaceFolder}/.env.staging",
  "console": "integratedTerminal",
  "justMyCode": true
}
{
  "name": "Node: Express (staging)",
  "type": "node",
  "request": "launch",
  "runtimeExecutable": "npx",
  "runtimeArgs": ["ts-node"],
  "args": ["src/main.ts"],
  "envFile": "${workspaceFolder}/.env.staging",
  "console": "integratedTerminal"
}

Conditional Breakpoints

VS Code supports conditional breakpoints (set via right-click on the breakpoint gutter). Common patterns:

# Python: Break only when user_id matches
# Condition: user_id == "admin"
def process_request(user_id: str, data: dict) -> dict:
    result = validate(data)  # Set conditional breakpoint here
    return result
// TypeScript: Break on specific iteration
// Condition: i === 42
for (let i = 0; i < items.length; i++) {
  processItem(items[i]);  // Set conditional breakpoint here
}
// Go: Break when error is non-nil
// Condition: err != nil
result, err := db.Query(ctx, query)
// Set conditional breakpoint on next line
if err != nil {
    return err
}

Troubleshooting

Python Debugger Not Attaching

# Verify debugpy is installed
pip install debugpy

# Verify port is open
lsof -i :5678

# Test from container
docker exec -it <container> python -c "import debugpy; print('OK')"

Node.js Source Maps Not Working

{
  "resolveSourceMapLocations": [
    "${workspaceFolder}/**",
    "!**/node_modules/**"
  ],
  "outFiles": ["${workspaceFolder}/dist/**/*.js"],
  "sourceMaps": true
}
# Verify TypeScript source maps are generated
cat tsconfig.json | grep sourceMap
# Should include: "sourceMap": true

Go Delve Connection Refused

# Verify Delve is installed
go install github.com/go-delve/delve/cmd/dlv@latest

# Verify port is open
lsof -i :2345

# Verify binary was built with debug flags
go build -gcflags="all=-N -l" -o server ./cmd/server

Docker Debug Port Not Accessible

# Verify port mapping
docker compose ps
# Should show 0.0.0.0:5678->5678/tcp

# Verify debug listener is running inside container
docker exec -it <container> netstat -tlnp | grep 5678
# Ensure ports are exposed in docker-compose.yml
services:
  api:
    ports:
      - "5678:5678"

Kubernetes Port-Forward Fails

# Verify pod is running
kubectl get pods -l app=api-server

# Check pod logs for debug listener
kubectl logs deployment/api-server | grep -i debug

# Manual port-forward to verify
kubectl port-forward deployment/api-server 5678:5678

Reference

VS Code Variables

Variable Description
${workspaceFolder} Root path of the workspace
${file} Currently opened file
${relativeFile} Currently opened file relative to workspace
${fileBasename} File name without path
${fileDirname} Directory of the current file
${input:id} Prompts user for input at launch

Debug Port Conventions

Language Default Port Protocol
Python (debugpy) 5678 DAP
Node.js 9229 Chrome DevTools Protocol
Go (Delve) 2345 DAP

External Resources