The engagement was quoted, signed and delivered late by a third. When we reconstructed what happened, the original estimate turned out to have been broadly accurate. What nobody had priced were nine change requests raised across four months — a new export format, an extra role in the permissions model, a different payment provider, and six more of that size. Not one of them was unreasonable. Not one of them had a number attached before the work started.
Why change requests, not estimates, decide the final invoice
Outsourcing discussions spend almost all their energy on the initial estimate. That is the wrong place to spend it. An estimate is a single judgement made once, with the most information anyone will ever assemble about the project, and it is usually wrong by a predictable and survivable margin.
Change requests are different in kind. They arrive one at a time, each too small to justify a formal process, each raised by someone with a legitimate reason, and each evaluated in isolation. Nobody is ever in a position to say “this is the one that broke the budget”, because individually none of them did. The mechanism is cumulative and it is invisible unless somebody is deliberately keeping a running total.
What follows is the seven-step method we use on Node.js engagements with UAE clients. It is deliberately administrative. It is designed to be run by a delivery manager rather than a lawyer, and it works under fixed price and time-and-materials alike.
What we got wrong the first time
We used to treat change control as a contractual formality to be invoked when things went badly, which meant it was never invoked until the relationship was already damaged. Raising a change request for the first time in month four sends an unmistakable signal: we are now in a dispute. So nobody raised one, small changes were absorbed as goodwill, and goodwill ran out precisely when the schedule became critical. The fix was not a stricter contract. It was to run the process from day one on changes so trivial they cost nothing — so that by the time a real one arrived, filling in the form was routine rather than an act of aggression.
Step 1 — Freeze a baseline someone can test against
A change request is defined entirely by what it changes. If the baseline is a feature list, there is nothing to measure against and every disagreement is settled by whoever has more leverage that week.
Write the scope as testable acceptance criteria. The practical test is whether a person who was not in the room can read a criterion and decide, without asking anyone, whether the delivered software satisfies it. “User management” fails that test. “An administrator can invite a user by email, the invitation expires after seven days, and an expired invitation returns a specific error rather than a generic failure” passes it.
For Node.js work specifically, three areas generate more disputes than the rest combined, and they are worth writing out even when they feel obvious:
- API contract boundaries — exact payload shapes, error formats, pagination behaviour and versioning policy. “A REST API” is not a baseline.
- Non-functional expectations — concurrent users, acceptable response times, and the payload sizes the system must accept. These are almost never written down and are the single largest source of “that was always implied”.
- Third-party integrations — which provider, which version, who owns the account, and what happens when the provider changes their API mid-project.
Both parties sign the baseline. It does not need to be long; it needs to be decidable.
Step 2 — Classify every request before anyone mentions money
Every incoming request falls into exactly one of three buckets, and the bucket determines who pays. Deciding the bucket first, in writing, prevents the conversation collapsing into a negotiation about price in which the underlying facts are never established.
- Clarification — the baseline covered this, it was ambiguous, and the parties are agreeing what it meant. No charge, no schedule impact. Record it so the same ambiguity is not re-litigated in month three.
- Defect — the software does not do what the accepted baseline says. Vendor cost, no schedule extension.
- Change — the baseline itself is moving. Client cost, priced under steps three and four.
The honest part of this method is admitting that a fourth category exists in practice: requests that genuinely sit on the boundary because the baseline was silent. Do not pretend those away. Name them, and apply a pre-agreed default — we usually split the cost of boundary cases below a stated value and escalate the ones above it, which removes the incentive for either side to argue about small items.
Step 3 — Price the change before a line of code is written
This is the step that does the actual work, and it is the one most often skipped because skipping it feels cooperative. An engineer who says “that is small, I will just do it” is being helpful and is also removing the only moment at which the cost was visible.
Require a written quote with four separate lines:
- Build effort — the part everybody estimates.
- Test effort — writing and running tests for the new behaviour.
- Documentation — API docs, runbook updates, anything a future engineer needs.
- Regression impact — retesting already-accepted functionality that this change touches.
The fourth line is almost always absent from vendor quotes and is frequently the largest. A two-day change to a shared data model or an authentication path can carry a week of retesting, and when that cost is invisible it is absorbed silently by the schedule instead of the budget. Ask for the decomposition even when you intend to accept the total — the conversation it triggers about what the change actually touches is worth more than the number.
Give the quote a validity period, typically two weeks. Estimates made against a codebase that has since moved on are not estimates.
Running a Node.js engagement that is drifting?
We can review the change register and the baseline and tell you where the cost is actually going — usually in a single session.
Get startedStep 4 — Set a threshold and name the approver
Write down, before kickoff, a single currency amount. Below it, the delivery lead approves changes in writing without escalation. Above it, the budget owner approves. Both roles are named individuals, not job titles, with a stated response time — two working days is a reasonable default.
The failure this prevents is specific and common. A product manager agrees to a change in a video call. The vendor builds it in good faith. The invoice arrives and the finance owner refuses it because nobody with budget authority approved anything. Everyone behaved reasonably and the money is already spent. In the UAE this is compounded when the approving stakeholder and the delivery team sit in different time zones, because the informal check-in that would have caught it never happens.
Approvals must live in a durable written channel. A message in the project channel is sufficient; a decision in a meeting with no written trace is not, regardless of how many people heard it.
Step 5 — Track cumulative drift, not individual requests
Keep one register. Every approved change, its classification, its priced value, its schedule impact, and a running total expressed as a percentage of the original contract value.
The percentage is the entire point. A nine-thousand-dirham change looks trivial in isolation and looks different when the line above it reads “cumulative approved changes: 31% of contract value”. The ninth request in our opening example was approved by people who had genuinely never seen the first eight added together, because nobody had ever put them on one page.
Review the register fortnightly with both parties present, and agree two trigger points in advance: a percentage at which the remaining scope is formally re-planned, and a percentage at which the engagement is re-scoped or re-contracted. Setting those thresholds while everyone is calm is far easier than deriving them during an overrun.
Step 6 — Write the disputed-change procedure before the first dispute
Sooner or later a request will be classified as a change by one party and a defect by the other, both in good faith, because the baseline was silent on the point. What matters is having decided in advance how that is resolved.
Three things need to be written down:
- Who decides — typically a named person on each side who escalate jointly, with a fallback if they cannot agree.
- On what evidence — the signed baseline and the written change register, not recollections of calls.
- Whether work continues meanwhile — our default is that the vendor proceeds under protest on anything below the approval threshold, so the schedule does not become a hostage in a commercial argument. Above it, work stops.
Contractual mechanics differ meaningfully depending on whether you are contracting through a mainland entity, a free zone company, DIFC or ADGM, and the same wording does not behave identically in each. That is a question for counsel rather than a checklist, and it is worth asking once, at contract stage, rather than during a dispute. The related point on ownership is covered in our notes on intellectual property terms in UAE developer contracts.
The pattern we see most often
Clients who have been burned once respond by making change control adversarial: heavier forms, longer approval chains, more signatures. It reliably backfires. When raising a change costs a week of process, the vendor stops raising them and starts absorbing small items silently, which sounds like a win until you discover that “absorbed” means the corners were cut somewhere you cannot see — usually in tests. The objective is not to make changes hard. It is to make them visible and priced. A process that takes ten minutes and always happens beats one that takes a week and is routinely avoided.
Step 7 — Reconcile at delivery and keep the register
At handover, run a line-by-line reconciliation: every entry in the change register against every invoice, with unbilled approved changes and billed unapproved changes both flagged explicitly. Do this before final acceptance, while you still have commercial leverage and while the people involved still remember the detail.
Then keep the register. It is the most useful estimating artefact you will produce, because it is a record of what your organisation actually failed to specify. Teams that read their last register before writing the next baseline typically find that the same two or three categories recur — non-functional requirements, integration edge cases, permissions models — and writing those into the next specification is worth more than any improvement in estimating technique.
The same discipline carries into how you scope a build in the first place; our walkthrough of scoping a SaaS build in Dubai covers the upstream half of this problem.
What the method costs to run
Roughly half a day to write the baseline properly on a small engagement, ten to twenty minutes per change request, and an hour every two weeks for the register review. On a six-month project that is a few days of effort in total.
Set against that: the engagement we opened with ran roughly a third over budget, and the dispute about who owed what took longer to resolve than several of the changes took to build. The method does not prevent change — change is normal and usually correct, because you learn things during a build that you could not have known when you scoped it. It prevents change from being invisible, which is a different and much more achievable goal.
The mechanics travel across markets with only the contractual layer changing. Our Singapore team runs the identical register with different governing-law provisions, and our US practice reports the same finding on the fourth quote line: regression impact is the cost nobody quotes and everybody pays.
Frequently asked questions
What counts as a change request rather than a bug?
A defect is the delivered software failing to do what the accepted baseline says it should do; the vendor fixes it at their cost. A change is the baseline itself moving; you pay for it. Everything difficult sits in the gap between them, and that gap is a function of how precisely the baseline was written. If the specification said “users can upload a document” and the delivered feature rejects a forty-megabyte file, there is no factual answer to whether that is a defect or a change, because the baseline never mentioned size. This is why step one is not optional: vague baselines do not create flexibility, they create arguments that are resolved by whoever has more leverage at the time.
How much should a change request cost?
There is no useful benchmark rate, and asking for one is usually a sign that the estimate is not being read. What matters is that the quote is decomposed: build effort, test effort, documentation, and regression impact on already-accepted work. The fourth line is the one that is almost always missing and almost always the largest. A change that takes two days to build can require five days of retesting if it touches authentication or a shared data model. When a vendor quotes a single undifferentiated number, ask for the decomposition before negotiating the total; in our experience the conversation about scope that follows is worth more than any discount you would have won.
Should we use fixed-price or time-and-materials to avoid change requests?
Neither model removes change requests; they relocate the argument. Fixed price concentrates it at the boundary of scope, which makes the vendor defensive about every request and slows delivery. Time and materials removes the boundary and relocates the argument to velocity and value, which is harder to audit and is where budgets quietly disappear. What actually controls cost in both models is the same discipline: a testable baseline, written classification, priced-before-started changes and a visible cumulative total. Teams that have those do fine under either contract; teams that do not are equally exposed under both, and the contract type becomes a post-hoc explanation for the overrun.
Who should approve change requests on the client side?
One named person per threshold, documented before kickoff, with a stated response time. The failure mode is not a bad approver, it is an ambiguous one: a product manager verbally agrees to a change in a call, the vendor builds it, and the finance owner refuses the invoice on the grounds that nobody with budget authority approved anything. Both parties are acting in good faith and the money is already spent. Define a value below which the delivery lead can approve in writing without escalation, and above which the budget owner must, and require that approvals exist in a durable written channel rather than in a meeting.
Starting a Node.js engagement and want the baseline right first time?
We write testable acceptance criteria and the change-control mechanics with you before the contract is signed — which is the only point at which it is cheap.
Get started