The single largest cost driver is rarely the technology stack — it remains how much is still undecided. Every ambiguity in the brief is converted into padding inside the number you receive. A supplier that cannot see what happens on the unhappy path has to assume the worst. Spending a week on a discovery phase frequently cuts the final cost much more than negotiating the rate.
Third-party integrations are the second big multiplier. A form that saves data is predictable; the same feature talking to an old accounting system is another matter entirely. The unknown sits in the counterparty: poor documentation, slow approval cycles, ecommerce development company fields that mean something different on each side. Ask each bidder to price integrations separately, since this is where estimates break.
Non-functional requirements quietly rewrite the budget. An internal tool used by twenty people costs far less than the same idea serving thousands of external customers. Audit and compliance requirements, availability guarantees, scalability, data retention rules and end to end project development localisation each add real engineering time. Write them down at the start or you can expect them priced as extras.
The team you are quoted matters a great deal. A day rate says little on its own: an experienced hire senior node.js engineer at a higher rate frequently turns out to be cheaper overall than two inexperienced developers who require constant review. Check too which roles are billed: delivery management, testing, release engineering and design are real work, but these should be named rather than hidden inside a blended rate.
The number in the proposal is rarely what you will actually spend. Budget for hosting, paid APIs, logging and aso service provider alerting and a change budget each year. A common working assumption holds that any production system requires a meaningful share of the initial investment per year simply to stay current. Treating the launch as the finish line is the classic mistake.