Navigate the transition to engineering management successfully. Covers listening tours, relationship building, team assessment, establishing credibility, avoiding common pitfalls, and the patterns that set new managers up for long-term effectiveness.
Engineering managers stepping into a new team or organisation face a narrow window to shape culture, align priorities, and build trust. The first 90 days are not just a period of observation but a deliberate, structured effort to internalise the engineering ecosystem, identify key friction points, and lay the groundwork for long-term impact. This page outlines a concrete, executable plan for an engineering manager to become a trusted leader within 90 days, grounded in real tools, workflows, and common failure modes.
Begin by compiling a living inventory of the engineering system. Start with git and kubectl, the two most ubiquitous tools across engineering teams.
$ git clone https://github.com/org/repo.git
$ cd repo
$ git log --since="90 days ago" --pretty=format:"%h %ad %s" --date=short
$ git branch --all --contains=HEAD
Review the main branch history for the past 90 days. Look for:
release/* branches with no CI/CD pipeline tracesUse kubectl to inspect the current deployment state:
$ kubectl get pods -A -o wide
$ kubectl get deployments -A
$ kubectl get services -A
$ kubectl get configmaps -n prod
$ kubectl get secrets -n prod
Check for drift: do configmaps and secrets in prod match those in staging? Use diff to compare:
$ kubectl get configmap app-config -n staging -o yaml > staging.yaml
$ kubectl get configmap app-config -n prod -o yaml > prod.yaml
$ diff staging.yaml prod.yaml
If the diff shows mismatched values in app-config, investigate how the config is applied: is it mounted as a volume? Is there a helm upgrade command that’s not run regularly?
Examine the CI/CD system as a black box: what happens when a commit is pushed?
Locate the CI configuration file—typically .gitlab-ci.yml, .github/workflows/ci.yml, or circleci/config.yml. Open it and study:
test, lint, build, deploycache keys and artifacts between jobsneeds and needs: [job] dependencieswhen and rules conditions for deploymentRun a local CI simulation:
$ git checkout -b feature/new-login
$ echo "new feature" >> README.md
$ git commit -m "Add login screen"
$ git push origin feature/new-login
Then, verify that the pipeline triggers and runs. Check the logs for:
npm install timingjest test output: 15 tests, 12 passed, 3 faileddocker build output: Successfully built 8d9e1f2a3b4cLook for silent failures: a test suite passes, but the coverage report is missing, and the build artifact is not uploaded.
Check deployment logs:
$ kubectl logs deployment/web-app -n prod
$ kubectl logs deployment/web-app -n prod --since=1h --tail=100
If the logs show Error: Failed to connect to database, investigate the DATABASE_URL in secrets and configmaps. Confirm that DATABASE_URL is set in the deployment manifest:
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: db-credentials
key: url
If db-credentials secret is missing, the app fails silently with Connection refused: 127.0.0.1:5432.
Examine the incident tracking and response system. Start with the issue tracker: GitHub Issues, Jira, or Linear.
Query for recent incidents:
SELECT id, title, status, created_at, updated_at
FROM incidents
WHERE created_at >= NOW() - INTERVAL '90 days'
ORDER BY created_at DESC;
For each incident, check:
#incident channeldocs/postmortems/pagerduty alert or alertmanager notificationLook for common failure patterns:
P0 but no on-call engineer assignedSLO dashboard showing 99.5% uptime, but the incident list shows 4 outages in the last 30 daysslack message: App is down: 500 error on /api/v1/usersCheck the SLO configuration. Look for service-level-objectives.yaml in the repo:
slos:
- name: "API Response Time"
metric: "http_request_duration_seconds"
target: 0.5 # 500ms
window: "7d"
threshold: 0.95 # 95% of requests under 500ms
If window is 7d but the dashboard updates hourly, the SLO is not being evaluated daily. Check the prometheus query for the SLO:
rate(http_request_duration_seconds_sum[7d]) / rate(http_request_duration_seconds_count[7d])
If this returns 0.47, the SLO is failing. Investigate why: is the http_request_duration_seconds metric not being recorded?
Schedule 1:1s with each member of the engineering team, plus product managers, UX designers, site reliability engineers, and key business stakeholders.
Use a shared Google Docs template with the following structure:
## Background
- Role: [Engineering Manager, Product Manager, etc.]
- Team: [Team name or function]
## Key Goals
- [List 3–5 priorities from their perspective]
## Current Challenges
- [What keeps them up at night?]
## Feedback on Engineering Manager
- [What do they expect from you?]
- [What would make your role successful?]
During the session, ask:
Document the responses and send a summary email within 24 hours.
Identify how decisions are made and documented.
Review the decision-records/ directory. Check the structure of a typical decision record:
---
title: "Choose Redis over Memcached for caching layer"
date: 2024-03-15
author: "Jane Doe"
status: "final"
context: |
Our app is experiencing slow API response times under load. We evaluated three caching solutions: Redis, Memcached, and DynamoDB.
Redis is more feature-rich but requires more operational overhead.
Look for:
pros and cons sectiondecision criteria tableimplementation planimpact on other systemsCheck if decisions are linked in the issue tracker:
Related: #123 reference in the PR that implements the decision?#decision tag in Jira or Linear?Verify that the decision is visible to others:
docs/ directory?README.md or CONTRIBUTING.md?If the decision record is not linked from the PR, ask: “Why didn’t we link the decision to the implementation?”
Attend the next sprint review and retrospective. Prepare a checklist:
Mad/Sad/Glad, Start/Stop/Continue)After the session, review the retrospective notes:
## Action Items from Retrospective
| Task | Owner | Due |
|------|-------|-----|
| Fix broken CI build | Alex | 2024-05-10 |
| Add API docs to Swagger | Sam | 2024-05-15 |
| Review on-call rotation | Priya | 2024-05-12 |
Verify that the due dates are in the calendar, and that the owner has a task in Jira or Linear.
Create a 30-60-90-day-plan.md file in the team’s docs/ directory.
# 30-60-90 Day Plan: Engineering Manager
## 30 Days
- Complete 1:1s with all engineering team members
- Review CI/CD pipelines and identify 2 critical issues
- Attend 2 sprint reviews and 1 retrospective
- Present findings in team meeting
## 60 Days
- Propose and lead a decision on one major engineering process
- Implement a new onboarding checklist for new engineers
- Review and refine the incident response playbook
- Conduct a team-wide tech talk
## 90 Days
- Deliver a summary of first 90 days to leadership
- Finalize the 30-60-90 plan with team input
- Launch a quarterly engineering review meeting
- Publish a team health report (based on 1:1s, retrospectives, and metrics)
Share the plan in a #engineering Slack channel and gather feedback.
test job runs, but the test output is not logged in the CI UI. The jest command is run, but --coverage is missing.build job produces a .tar.gz artifact, but it’s not uploaded to S3 or GitHub Releases.deploy job fails silently: the kubectl apply command runs, but no rollout status is checked.Fix by:
# Add rollout status after apply
kubectl apply -f k8s/manifests/ -n prod
kubectl rollout status deployment/web-app -n prod --timeout=60s
Add a check step in the CI config:
- name: Check rollout
run: |
kubectl rollout status deployment/web-app -n prod --timeout=60s || {
echo "Rollout failed"
kubectl describe deployment web-app -n prod
exit 1
}
staging and productionstaging and prod configs are similar but not identical.staging uses redis://staging-redis:6379, but prod uses redis://prod-redis:6379.prod has env: production, but staging has env: staging.The app logs show Error: Cannot connect to Redis: Connection refused, but redis://staging-redis:6379 is reachable from staging.
Solution: create a config diff script:
#!/bin/bash
# diff-configs.sh
set -e
for env in staging prod; do
kubectl get configmap app-config -n $env -o yaml > $env-config.yaml
done
diff staging-config.yaml prod-config.yaml
Run this script monthly and add it to the ci pipeline.
PR description is missing the related issue link.merge request has WIP label, but no Ready for Review status.Fix by creating a PR template:
## Description
<!-- Describe the change briefly -->
## Related Issues
- Fixes #123
- Closes #456
## Checklist
- [ ] Tests added
- [ ] Documentation updated
- [ ] Performance impact evaluated
- [ ] CI passes
- [ ] Deployment script included
Enforce the checklist with GitHub Actions:
- name: Check PR checklist
run: |
if ! grep -q "## Checklist" .github/pull_request_template.md; then
echo "PR template missing checklist"
exit 1
fi
first-90-days-summary.md document with:team-onboarding-checklist.md for new engineersdecision-record for one major process changeCI/CD health report with findings and recommendationssprint review and retrospective template used in team meetingsThese deliverables are not just documents—they are living artifacts, updated with every iteration.
This page was rewritten on 17 October 2026. It replaced a templated version that was not specific to its own title. How these pages are written and checked. If anything here is wrong, tell us at [email protected] and we will correct it.
We use cookies for analytics (Google Analytics) and advertising (Google AdSense) to improve your experience and support free content. Privacy Policy