For the first three years of my career I said yes to everything. New ad-hoc query? Sure. Production hotfix on a Friday at 5 p.m.? On it. Add a tenth filter to a dashboard that already had nine? Why not. I thought I was being helpful. What I was actually doing was training the people around me to expect that everything was a priority, which is a polite way of saying nothing was.
The week I burned out, I learned that saying yes to one thing is, mathematically, saying no to something else. You just don’t always know what. Usually it’s sleep, or the long-term project that keeps slipping, or the documentation you swore you’d write. The bill comes due either way.
So I had to learn to say no. And the bad news is that “no” by itself is almost always the wrong answer at work. The good news is there’s a small set of moves that let you push back without becoming the bottleneck everyone resents.
”No” is rarely a complete sentence at work
Outside of work, “no” is a complete sentence and you should use it. At work, a flat no usually leaves the other person with the same problem they walked in with, plus a bad taste about you. Even when the no is correct, the delivery matters. You’re not there to be a gatekeeper. You’re there to be a thinking partner who occasionally has to say “this isn’t the right move.”
The shape of a useful no almost always includes three things: an acknowledgement of what they actually need, an honest constraint that prevents the literal request, and an alternative path that gets them closer to what they want. If you can hit all three, the conversation goes from “engineering said no again” to “we worked out a smaller version that lands next sprint.”
That’s not a script. It’s a habit. And like most habits, it gets easier with reps.
The trade-off framing
The single most useful sentence I’ve ever picked up at work is “I can do X if we drop Y.” It does two things at once. It honours the request, because you’re saying yes in principle. And it reveals the cost, because you’re forcing the other person to engage with the fact that engineering capacity is finite.
A PM I worked with once asked our team to ship a real-time alerting layer in two weeks, on top of an unrelated migration we’d already committed to. The old me would have said “we’ll see what we can do” and then quietly worked weekends. The me that had been burned a few times said “I can ship a v1 of the alerting in two weeks if we push the migration to next quarter. Which one matters more right now?”
He thought about it for ten seconds and said the migration mattered more. We ended up agreeing on a five-minute batch alerting layer instead of real-time, which solved 90% of the actual use case in 20% of the time. Nobody felt steamrolled. The trade-off was on the table, in plain language, and we picked together.
That’s the move. Don’t decide unilaterally that they can’t have the thing. Make the cost visible and let them decide.
”Help me prioritise”
There’s a related move I use when someone keeps adding tickets to the queue without acknowledging that I have a queue. Instead of saying “I’m too busy”, I say “here’s what I’m currently working on, in this order. Where would this new thing fit?”
Sometimes the answer is “above number two”, and now I know to bump something. Sometimes the answer is “oh, actually it’s not that urgent, put it at the bottom.” Sometimes, and this is my favorite, the answer is “actually, never mind, I’ll figure it out myself”, which is a wonderful sign that the request wasn’t really worth doing in the first place.
The framing matters. You’re not refusing. You’re handing them the visibility they need to make a real decision. If they pull rank and tell you everything is urgent, that’s information too. It tells you the team has a planning problem and you should escalate, not absorb.
”Yes, but here’s a smaller version”
This is the move I reach for when the request itself is reasonable but the scope is wildly out of proportion to the value. Someone wants a full self-service analytics platform, and what they actually need is a Postgres view and read access to it.
The way I frame it: “Yes, we should do this. The full version you described is roughly two months of work. Before we commit to that, I’d like to ship a tiny version next week that solves 80% of the use case, and see if the remaining 20% is actually worth the rest of the time. Sound okay?”
That sentence is doing a lot. It validates the underlying problem. It gives an honest estimate of the big version. It commits to action, fast, on a small version. And it builds in a checkpoint where the bigger investment is re-evaluated. Eight times out of ten, the small version is enough and the big version quietly gets dropped without anyone losing face.
I once used this to head off a request for a custom workflow tool. The team wanted Airflow plus a custom UI plus role-based access plus a Slack bot. I asked if I could spend two days plumbing their existing process into the Airflow we already had, with a basic Slack notification on failure. Two days became the permanent solution. The custom UI was never missed.
When to escalate, and how
There’s a category of “no” you can’t say on your own, and it’s important to recognise it. If a request is going to materially affect another team, change a deadline that’s been promised externally, or break something the company has publicly committed to, that’s not your no to give.
Escalating is not snitching. Escalating is being honest about who has the authority to make the call. The script I use is something like: “I don’t think we should do this, and here’s why, but the call is bigger than my team. Can we get [manager / PM / whoever] in the loop before we commit?”
That sentence protects you, because you’re not the one blocking the work. It protects the company, because the right person makes the call. And it protects the relationship with the person making the request, because you’re not unilaterally shutting them down. You’re routing them to someone who can actually answer.
The mistake I see junior engineers make is the opposite. They say a quiet, hedged maybe, the work creeps forward, and three weeks later the team realises they’ve shipped half of something nobody approved. Then everyone is annoyed and the engineer takes the hit. Escalating early would have been kinder to everyone, including future-them.
Saying no is a skill, and skills take practice
The thing I most want to tell my younger self is that pushing back at work is a learnable skill, not a personality trait. You don’t have to be a “natural” at it. You learn it the same way you learned SQL: badly at first, then mediocre, then okay, then somewhere around year five it starts to feel natural.
The first few times you’ll over-rotate. You’ll say no when you should have said yes, or you’ll soften the no into a yes by accident. You’ll have a manager push back hard and you’ll cave. That’s fine. Reflect after the meeting, write down what you wish you’d said, and next time you’ll say a little more of it.
The alternative, silent compliance, is what burned me out. It’s also, ironically, what makes you less valuable to the team in the long run. The engineer who says yes to everything is the engineer whose code review feedback nobody trusts, because they’ve never seen them push back on anything. Saying no, well and kindly, is part of how you earn the right to be listened to when something actually matters.
The codebase you work in, the team you’re on, and the career you’ll have ten years from now are all built out of small “no, but here’s a better idea” moments. None of them feel important when you’re having them. All of them add up.