Engineering OKRs That Drive Results: Setting Technical Goals, Measuring Impact, and Avoiding Vanity Metrics
Most engineering OKRs measure activity instead of outcomes. This guide covers how to write measurable technical objectives, align them with business goals, and run a review cadence that actually works.
Most engineering OKRs fail silently. The team ships them at the end of the quarter, marks everything green, and nothing actually changed for users or the business. The reason is almost always the same: the OKRs measured activity instead of outcomes.
“Completed 47 story points” tells you the team was busy. It says nothing about whether the product got faster, more reliable, or easier to operate. “Merged 120 PRs” tells you the team made commits. It says nothing about whether those commits improved anything. These are vanity metrics with a goal-setting format applied on top.
Engineering OKRs have a structural problem that product OKRs do not. Product teams can point at user metrics: activation rate, retention, conversion. Engineering teams often own work that sits between the system and the user, which makes the connection to outcomes feel indirect. That indirection is not a reason to fall back on activity metrics. It is a reason to think harder about what you are actually trying to change.
Why Engineering OKRs Are Different From Product OKRs
Product OKRs map naturally to user behavior because product changes are visible to users. Engineering OKRs cover system properties that users experience indirectly: reliability, performance, deployment safety, developer productivity.
This creates two failure modes. The first is ignoring the engineering layer entirely and forcing engineering teams to adopt product metrics they do not control. A database team cannot own “user activation rate.” The second failure mode is retreating to pure activity metrics because the outcome is hard to measure. Neither approach works.
The right framing for engineering OKRs is: what system property are you changing, and what is the measurable signal that the property actually changed?
System properties that matter:
- Reliability: the rate at which the system fails and how quickly it recovers
- Performance: latency at specific percentiles for specific operations
- Developer experience: how long it takes engineers to go from idea to production
- Security posture: the exposure surface and the time to detect and resolve incidents
- Operational efficiency: how much infrastructure cost it takes to serve a unit of load
Each of these has concrete, measurable signals. None of them require activity counts.
A Framework for Writing Measurable Technical Objectives
An OKR has two parts: the objective (what you want to change) and the key results (how you know you changed it). Engineering teams usually write the objective well and then collapse the key results into task lists.
A key result must be:
- Measurable: a number you can pull from a system, not a judgment call
- Outcome-oriented: reflects the state of the world, not the work done to get there
- Attributable: the team’s actions can plausibly move this number
Here is a TypeScript type that captures what a well-formed engineering key result looks like:
type KeyResult = {
description: string;
baseline: number; // current measured value
target: number; // what "success" looks like
unit: string; // p99 latency in ms, incidents per month, etc.
dataSource: string; // where this number comes from — no judgment calls
cadence: "weekly" | "bi-weekly" | "monthly";
};
type EngineeringOKR = {
objective: string; // qualitative direction: "make the API reliable enough to trust"
quarter: string;
owner: string;
keyResults: KeyResult[];
};
// Example
const reliabilityOKR: EngineeringOKR = {
objective: "Reduce unplanned downtime to the point where on-call is not a burnout risk",
quarter: "Q2 2026",
owner: "Platform team",
keyResults: [
{
description: "Reduce P1 incident count",
baseline: 8,
target: 2,
unit: "incidents per month",
dataSource: "PagerDuty incident log, severity P1 filter",
cadence: "monthly",
},
{
description: "Reduce mean time to resolution for P1 incidents",
baseline: 94,
target: 30,
unit: "minutes",
dataSource: "PagerDuty MTTR report",
cadence: "monthly",
},
{
description: "Reduce on-call pages during sleeping hours",
baseline: 12,
target: 3,
unit: "pages per engineer per month between 10pm-7am",
dataSource: "PagerDuty schedule + escalation log",
cadence: "monthly",
},
],
};
The dataSource field is non-negotiable. If your key result can only be measured by asking someone to manually count things or by inspecting Jira, it will not get measured consistently. If it lives in a dashboard query or a CLI command, it will.
Good vs Bad OKR Patterns
The distinction between a well-formed engineering OKR and a vanity OKR usually comes down to one question: does this number change when the system gets better, or does it change when the team is busy?
| Pattern | Bad OKR (activity) | Good OKR (outcome) |
|---|---|---|
| Reliability | ”Complete 15 runbook updates" | "Reduce MTTR for P1 incidents from 94m to 30m” |
| Performance | ”Profile 8 slow endpoints" | "Reduce API p99 latency from 2,100ms to 400ms for the /search endpoint” |
| Developer experience | ”Migrate CI to new runner fleet" | "Reduce median CI build time from 18 minutes to 6 minutes” |
| Security | ”Conduct quarterly security review" | "Reduce mean time to patch critical CVEs from 21 days to 3 days” |
| Infrastructure | ”Right-size 30 EC2 instances" | "Reduce monthly compute spend per 1,000 active users from $420 to $180” |
| Developer onboarding | ”Update onboarding docs" | "Reduce time for a new engineer to merge their first production change from 9 days to 3 days” |
| Deployment safety | ”Add 20 integration tests" | "Reduce production rollbacks from 4 per month to 0 for the checkout service” |
Every “bad” OKR in this table has a team somewhere that would mark it green at end of quarter. The “good” version requires the system to actually be different.
OKR Examples by Domain
Reliability
Reliability OKRs should target specific, named services or behaviors. “Improve system reliability” is not an objective. “Make the payment processing path reliable enough that on-call engineers sleep through the night” is.
| Objective | Key Result | Baseline | Target | Source |
|---|---|---|---|---|
| Eliminate cascading failures in the order pipeline | P1 incident rate for order service | 6/month | 1/month | PagerDuty |
| Eliminate cascading failures in the order pipeline | Mean time to recovery for order service outages | 47 min | 12 min | PagerDuty MTTR |
| Eliminate cascading failures in the order pipeline | Percent of incidents with automated rollback | 10% | 80% | Deployment log |
Developer Experience
Developer experience OKRs are among the most impactful and most frequently written badly. “Improve developer experience” means nothing. “Reduce the time a developer spends waiting between writing code and seeing it run in staging” is measurable.
| Objective | Key Result | Baseline | Target | Source |
|---|---|---|---|---|
| Make the development loop fast enough to not interrupt flow state | Median CI build time | 18 min | 5 min | CI dashboard |
| Make the development loop fast enough to not interrupt flow state | Median time from PR open to first review | 26 hours | 4 hours | GitHub API |
| Make the development loop fast enough to not interrupt flow state | New engineer time-to-first-production-deploy | 9 days | 2 days | Onboarding tracker |
Infrastructure and Cost
Infrastructure OKRs should express efficiency in terms of cost per unit of business value, not total cost reduction. Cutting costs by 30% while cutting capacity by 30% is not an achievement.
| Objective | Key Result | Baseline | Target | Source |
|---|---|---|---|---|
| Reduce infrastructure cost without reducing capacity headroom | Cost per 1,000 API requests | $0.84 | $0.30 | CloudWatch + billing |
| Reduce infrastructure cost without reducing capacity headroom | P99 latency under 2x peak load | 3,400ms | 800ms | Load test results |
| Reduce infrastructure cost without reducing capacity headroom | Reserved instance coverage | 22% | 70% | AWS Cost Explorer |
Security
Security OKRs fail most often when they measure compliance activity instead of actual exposure. “Completed SOC 2 Type II audit” is a milestone, not a key result for a security OKR. The actual improvements are in exposure reduction and response time.
| Objective | Key Result | Baseline | Target | Source |
|---|---|---|---|---|
| Reduce the window between vulnerability disclosure and patch | Mean time to patch critical CVEs | 21 days | 3 days | CVE tracker |
| Reduce the window between vulnerability disclosure and patch | Percent of services with automated dependency scanning | 14% | 100% | CI config audit |
| Reduce the window between vulnerability disclosure and patch | Open critical vulnerabilities in production | 31 | 0 | Snyk dashboard |
Aligning Engineering OKRs With Business Goals
The most common complaint from engineering teams about OKRs is that leadership imposes business metrics (revenue, churn, conversion) and then expects engineering to own them, despite the fact that engineering cannot control those metrics directly. This is a legitimate complaint, but the solution is not to disconnect engineering OKRs from the business. It is to make the causal chain explicit.
The structure that works:
- Business goal: “Reduce churn by improving product reliability.”
- Engineering hypothesis: “If we reduce P1 incidents from 8 to 2 per month, support ticket volume will drop and NPS will improve.”
- Engineering OKR: “Reduce P1 incident rate for the core product from 8 to 2 incidents/month.”
This structure lets engineering own what it can actually move, while making the connection to the business outcome visible. It also creates a feedback loop: if you hit the engineering OKR but the business metric does not move, the hypothesis was wrong, which is useful information.
The TypeScript representation of this alignment:
type BusinessAlignment = {
businessGoal: string;
hypothesis: string; // if we do X, then business metric Y will improve because...
engineeringOKR: EngineeringOKR;
leadingIndicator: string; // what engineering measures; often daily/weekly
laggingIndicator: string; // what business measures; often monthly/quarterly
};
const alignedOKR: BusinessAlignment = {
businessGoal: "Reduce churn driven by reliability perception",
hypothesis:
"If P1 incident rate drops below 2/month and MTTR drops below 30 min, " +
"support escalation volume drops, which reduces churn in the enterprise cohort",
engineeringOKR: reliabilityOKR,
leadingIndicator: "P1 incident count and MTTR (PagerDuty, weekly)",
laggingIndicator: "Enterprise cohort 90-day churn rate (CRM, monthly)",
};
The leading/lagging indicator split is how you avoid two failure modes: engineering claiming credit for business outcomes they did not cause, and business stakeholders dismissing engineering work because the P&L has not moved in the six weeks since you shipped.
Cadence and Review Processes That Work
OKRs need a review cadence that surfaces problems early enough to change course. A quarterly OKR with no mid-quarter check-in is a post-mortem format, not a management tool.
A cadence that works for engineering teams:
Weekly (15 minutes, async): Update the current values for each key result in a shared doc or dashboard. Flag blockers. No discussion unless something is moving in the wrong direction.
Bi-weekly (30 minutes, synchronous): Review current values vs target trajectory. For each key result that is off-track, identify whether the cause is execution (we did not do the work), hypothesis (the work we did does not move the metric), or measurement (we are measuring the wrong thing). Assign an owner to address it.
End of quarter (60 minutes): Score each key result honestly. 0.7 is a good score. 1.0 means the target was too easy. 0.3 means something went wrong. Write the retrospective before you start planning next quarter.
The key discipline is the bi-weekly block. It is where you catch the difference between “we are behind on the work” and “the work we are doing is not actually moving the metric.” The second failure mode is far more dangerous and far more common.
type OKRCheckIn = {
date: string;
keyResultId: string;
currentValue: number;
targetTrajectory: number; // where should we be by now given a linear path to target
status: "on-track" | "at-risk" | "blocked";
failureMode?: "execution" | "hypothesis" | "measurement";
blockerDescription?: string;
ownerAction?: string;
};
Tracking failure mode is important. If you mark a key result “at-risk” every week without distinguishing whether it is an execution problem or a hypothesis problem, you cannot fix it.
Common Anti-Patterns
Sandbagging
Setting targets low enough to guarantee a 1.0 score. This usually comes from a performance review culture where OKR scores matter for promotion. The fix is not to punish teams for 0.7 scores but to explicitly model what a 1.0 score means: the target was too easy.
If your team scores 1.0 on every key result every quarter, your targets are too conservative. An organization where every team consistently scores 1.0 is not a high-performing organization. It is an organization that has learned to game its OKRs.
OKRs as task lists
“Complete API documentation for 12 services” is a task. “Reduce time engineers spend looking for undocumented API behavior from 2 hours/week to 15 minutes/week” is a key result. The difference is not cosmetic. Task lists measure whether work was done. Key results measure whether the work mattered.
The test: can you complete every item on the list and still have the underlying problem get worse? If yes, it is a task list, not a key result.
Vanity metrics
A vanity metric moves in the right direction regardless of whether the system is actually improving. PR count is a vanity metric because merging more PRs does not mean faster feature delivery. Uptime percentage is a vanity metric when you are already at 99.9% because the marginal difference between 99.91% and 99.95% is invisible to users but easy to claim as progress.
| Vanity metric | What it actually measures | Better alternative |
|---|---|---|
| Story points completed | Team was busy | Feature delivery cycle time (PR to production) |
| PRs merged | Commits made | Deployment frequency with rollback rate |
| Uptime percentage (at 99.9%+) | No major outages | MTTR and P1 incident rate |
| Test coverage percentage | Tests exist | Defect escape rate to production |
| Tickets closed | Work was categorized as done | Bug count in production over time |
| Lines of code written | Team typed a lot | N/A — this is never useful |
Misaligned granularity
A team of five engineers with an OKR that is actually a company-level objective will score themselves green because they did their part, while the business outcome they were supposed to drive did not move. The inverse is also common: an individual engineer’s key result rolled up to a team OKR, obscuring whether the team actually improved.
The right granularity is: team-owned OKRs that the team can actually move, with explicit alignment to the next level up (business unit or company objective) documented as a hypothesis, not as a shared metric.
What Good Looks Like at Quarter End
A well-run engineering OKR quarter ends with:
- Two or three key results that scored between 0.6 and 0.8 (meaningful progress, realistic targets)
- At least one key result where you learned the hypothesis was wrong and can explain why
- A retrospective that tells the next quarter’s planning what to prioritize differently
- Data you can show anyone in the company without needing to explain what “story points” means
The goal is not a perfect score. The goal is a system where engineering work is legible to the rest of the organization, where the team knows whether it is actually improving what it set out to improve, and where the failures are informative rather than hidden.
Engineering that cannot measure its own outcomes is engineering that cannot argue for its own investment. Getting the OKR format right is not bureaucratic overhead. It is how you build the organizational evidence that the work matters.
More in Engineering Management
The AI Productivity Paradox: Why Your Team Ships More Code but Delivers Less
AI coding tools create an illusion of velocity at the individual level while degrading team-level delivery, quality, and maintainability. The core mechanism is a 5x+ senior/junior productivity split that aggregate metrics hide entirely.
The AI Productivity Paradox: Why Your Team Ships More Code but Delivers Less Value
93% of developers use AI coding tools, yet DORA metrics haven't improved proportionally. Individual output rises while bug rates, review times, and deployment instability climb. Here is why individual AI productivity gains create organizational drag, and how to fix it with architecture-level guardrails.
Why Your Engineering Team Is Shipping Slower Than 6 Months Ago
Engineering velocity declines at seed-to-Series-A startups for predictable, diagnosable reasons. Process debt, unclear ownership, hiring mistakes, burnout, and architectural bottlenecks all compound. Here is a diagnostic framework you can run in one afternoon, plus a tradeoffs table for each intervention.
The AI Ratchet Effect: Why Giving Your Engineering Team AI Tools Made Them Work Harder, Not Smarter
67% of engineers who adopted AI tools in 2025 worked more hours by year-end, not fewer. This is the AI ratchet effect: management converts every productivity gain into a permanently higher baseline. Here is how it happens, why it is worse at startups, and what a sustainable AI adoption cadence actually looks like.