The spec is 22 pages. Screens, features, a flow diagram, an appendix of nice-to-haves. You posted it, shortlisted five of 31 proposals, and the numbers came back at $4,800, $11,000, $26,000, $30,000 and one agency at $58,000. Three of them called the spec “very clear” and quoted without asking a question.
The real gotcha in hiring developers on Upwork to build a whole product is structural, not personal: a fixed price quoted against a written spec creates an adversarial relationship the moment reality departs from the spec, and reality always departs from the spec. From that hour, every discovery costs the developer money, so the rational move is to hide it, ship the cheapest interpretation, or pad the next change request. Nobody has to behave badly. The contract does it for them. Almost every horror story traces back to that single design choice, plus one more: nothing was ever deployed anywhere you own.
The contract shape matters more than which of the five you pick
One fixed price for the whole build feels safest because the number is known, and it is the worst option for a multi-month product. The developer priced a guess, and when the guess is wrong they absorb the loss. Nobody absorbs a loss quietly for three months, so you get scope fights, silence around week seven, or something that matches the document and is unusable. Open-ended hourly removes that incentive and replaces it with none at all, because nothing ever has to work. The work diary shows activity, not progress.
Milestone contracts with a written change process beat both, and the details carry it:
- One to two weeks per milestone, never more. Milestone length is your maximum loss and your maximum ignorance.
- Each milestone ends in a deploy you can click. The next section. It is the most valuable clause in the agreement.
- A change note template agreed up front: what changed, the hours, the new price, an emailed “approved” before work starts. No verbal changes.
- A discovery allowance, say 15% of the total, spendable only through change notes. This is what makes honesty affordable: when they find your CSV import has three date formats in it, they can tell you instead of guessing.
- Milestone one is a spike, not a feature. Three days: repository set up, pipeline running, a hello-world build live in your staging environment, a written note on the data model. You learn more that week than from any interview.
Your spec describes screens, not software
A spec written by a non-engineer omits five things every time, and each one is why the estimates diverge by a factor of six.
- States. Loading. Saved. Saving and failed. Offline. Stale data that looks current. Your document shows the happy version of each screen, so that is what got priced.
- Errors. The card declines. The upload is 400 MB. The API is down for nine minutes. What should happen is a product decision, and if you skip it, someone makes it for you at 2am, badly.
- Permissions and roles. Who can see, edit, delete, export, refund, impersonate. Most specs assume one kind of user and mention an “admin area” on page 19. Roles are architectural: adding a second one late is not a screen, it is a rewrite of every query.
- Empty and first-run cases. What does the dashboard show the day someone signs up with zero of everything, and what does that list look like at 40,000 rows?
- The data model. What things exist, which owns which, what is required, what can change after creation, what wins when two sources disagree. That is the actual product, and a document with no data section gets priced like a brochure.
The fix takes an afternoon and no technical skill. Add three lines under every screen: what it looks like with no data, what happens when the action fails, who is allowed to be here. Add one page naming the nouns in your product and which owns which. Then turn features into acceptance sentences you can personally run: “A logged-in coach uploads a 20 MB video, sees a progress bar, and the athlete gets an email within two minutes.” You can test that on a Tuesday. “Video module” you cannot, and “video module” is what you are buying.
The demo-versus-deploy gap, and the clause that closes it
This is how a marketplace build fails without anybody lying. Every fortnight you get a screen share and the app works. At handover you find it runs on their laptop, the database is a local copy, the keys are their personal keys, the “test site” was on their hosting, and there is no deployment process at all. Nothing ever ran in your infrastructure. What you own is a folder of code nobody alive knows how to start, and a demo is the artefact that hides exactly that.
So write the highest-value clause in the contract: a milestone is complete only when the work is running in the client’s own staging environment, deployed from the main branch of the client’s repository through an automated pipeline, using the client’s cloud accounts and keys, and reachable at a URL. Not a zip. Not a video. Not their server. A URL you open on your phone.
Deployment then gets solved in week one rather than in month four, and if the developer vanishes you have working software on infrastructure you control. Treat resistance as information.
Accounts and keys, settled before milestone one is funded
Source control in an organisation you created, on your billing, developer added as a member. Cloud accounts opened by you, on your card, their access scoped. Domain and DNS at a registrar in the company name. App store accounts in your company’s name with you as account holder, plus custody of the signing keys, because an app published inside someone else’s organisation is painful to reclaim. Every third-party API key under a company email address: payment gateway, transactional email, SMS, maps, error monitoring, AI APIs. Secrets in a password manager you own. One rule covers all of it: nothing critical lives under a personal email address, and keep a written inventory, because you cannot revoke access you never recorded granting.
Judging code you cannot read, and checking who wrote it
Three proxies, none needing you to read a line. Does it run from a clean clone? At milestone two, take the repository to a machine that never touched the project and follow the README. More than an hour and one call, or an answer of “I’ll do it on a screenshare”, means the project has a single point of failure with a laptop. Is there any test, and does anything run it? Not coverage targets: one automated test, executed on push. Zero tests and no pipeline means nobody can safely change this software once the author leaves, including the author. What shape is the commit history? Many small commits across the whole period, not one “initial commit” of 40,000 lines at handover, because then you cannot tell what was written when, by whom, or lifted from where.
That last one leads somewhere. Agencies are legitimate on Upwork and have their own profile type, so a team is not the problem; not knowing is. Upwork’s User Agreement has users agree not to maintain more than one account without written permission and “not to share your username or password with anyone,” bars false or misleading information about identity or location, and says users are solely responsible for verifying information about each other. Nobody is checking for you, so test it early. Ask in writing who else will touch this and whether they will be on calls. On video, have them open their editor and talk you through a commit from last week, because the author drifts into detail and the non-author gets vague. Compare commit author emails in your repository against the person you hired. Delegation is fine. Concealment predicts everything else.
What Upwork’s escrow covers, and who actually owns the code
Founders overestimate platform protection badly. From Upwork’s own pages at time of writing, and terms change. Fixed-price milestones are funded into escrow before work starts, $5 minimum per milestone, released when you approve or automatically 14 days after submission if you neither approve nor request changes, so ignoring a submission is not a defensive position. If you refuse to release, either side can dispute, and Upwork’s dispute page describes mediation by its own specialists producing a non-binding resolution: five calendar days for the other side to respond, two calendar days each to accept or reject, and a Notice of Non-Resolution if they decline, after which the only route left is binding arbitration bought from an external provider. Upwork also states a seven-day filing window, after which remaining escrowed funds return to the client. Hourly works differently: work diary snapshots show what was being worked on, and you can dispute the previous week’s hours where they do not qualify for Hourly Payment Protection, which does not cover bonuses, fixed-price projects or manually added time.
Escrow protects the money inside one milestone. It does not protect your timeline, your launch date, the eight weeks you lost, or code that exists and cannot be deployed. On a $30,000 build, the realistic worst case escrow covers is one milestone. The rest is protected by milestone size, the deploy clause and documentation.
Ownership is two layers, routinely conflated. Upwork’s User Agreement says service contracts are directly between users and that Upwork is not a party, and that the two of you may agree whatever terms you consider appropriate so long as they do not conflict with Upwork’s rights. Its Optional Service Contract Terms apply only where you have not agreed something conflicting, and Upwork describes them as provided “as a sample only”. Do not assume the platform assigned you anything.
Then get the wording right, because the popular phrasing is wrong for software. The US Copyright Office’s guidance is that a commissioned work is a work made for hire only if it falls within one of nine listed categories, there is a written agreement with the individuals who actually created it, the parties expressly agree it is a work made for hire, and all parties sign. Those nine are publishing and audiovisual categories, and software is not among them, so a contract leaning on work-for-hire language alone may assign you nothing. Use a present-tense assignment: the contractor hereby assigns all right, title and interest in the work product to your company upon creation, binding every subcontractor who touches it and surviving termination.
And the licence question nobody asks. Your product will be a little code your developer wrote and a lot of third-party packages, so make a written dependency and licence list a deliverable. Three things to look for: strong copyleft licences such as GPL or AGPL inside a product you plan to sell as closed source, which is a real problem and not a theoretical one; paid SDKs licensed to the developer rather than to you; and code carried over from a previous client, which was never theirs to give.
Make abandonment survivable, and watch scope move down as well as up
Abandonment is rarely dramatic. Replies slow, the demo slips a week, then two, then a family emergency, then nothing, and by the time you accept it you are two milestones past the last thing you saw working. Short milestones cap the damage. Three more practices turn what is left from fatal into annoying.
- Main branch always deployable, contractually. Work in progress lives on branches, so you lose the feature, not the product.
- Documentation as a per-milestone deliverable, not a report at the end, which never gets written. How to run it locally, how to deploy, where the data lives, what each environment variable does.
- A named second contractor who has already been paid. The item everyone skips and the one that saves projects. At milestone two, pay a different developer four to six hours to run the clean-clone test, deploy it themselves and write a one-page note. You get an independent read while you can still act on it, and someone who could start on Monday. Tell your primary developer; good ones are relaxed about it.
Everyone warns you about inflated scope. Under a fixed price the opposite is commoner and much harder to see. Quiet scope reduction: the admin panel becomes a raw database viewer, search becomes exact-match only, roles collapse to one, the notification email becomes a “coming soon” banner, the long list has no pagination because nobody tested 40,000 rows. Each substitution is defensible alone, each saves hours the developer is no longer paid for, and together they produce the demo that looks finished and falls over on day one of real use. Your defence is the acceptance sentences, run by you, on the staging URL, at every milestone, plus a rule that any change of approach needs a change note even when it costs nothing. You are not trying to prevent the change. You are trying to be told.
Two more things you are probably assuming rather than writing down. Overlap and response times: four hours of working-day overlap is the practical minimum, because most problems get solved by one quick exchange rather than a scheduled call, and a build contains several hundred questions. Add replies within one business day and notice before any absence over two days. Security basics, in the contract rather than in hope: no real customer data in a development environment; no keys committed to the repository, and any that are get rotated rather than deleted, because git history keeps them forever; least-privilege access scoped to staging; a written revocation list.
The handover checklist to run before final payment
Final payment is the last leverage you will ever have. Put this in the contract on day one so it is not a surprise, then release nothing until every line is true.
- All code in your repository, your organisation, full commit history.
- Current version deployed to your staging from main through the pipeline, and you opened it today. Production deployed by the same documented pipeline, not by hand.
- A fresh clone plus the README gets a second person running locally without phoning the developer.
- Every account and service in your name, on your billing, you as owner; every secret in your password manager; every key the developer created rotated; their access revoked item by item off the inventory.
- A written note on what runs where, the scheduled jobs, where data lives, and when a backup was last restored successfully.
- Dependency and licence list, every third-party service with its monthly cost, and design source files rather than exports.
- Signed IP assignment covering everyone who worked on it, dated back to the first commit.
- Every acceptance sentence executed by you on production, failures written down and either fixed or accepted.
Questions founders ask at this point
Is a marketplace simply the wrong place to build a whole product? No, but contract value and duration are the real risk variables, not the sourcing channel. A defined slice under a couple of months, structured as above, gives you a working first version and an honest read on the developer. A twelve-month six-figure programme run through a marketplace message thread by a founder who cannot read code is where this reliably breaks, and the fix is a managed team with an accountable contract, not a better freelancer.
They suggested working directly to avoid the fees. Not during the build. You would trade escrow, the work diary, the dispute process and the payment trail for a few percent, at the stage when you know least about this person. Upwork’s User Agreement also restricts off-platform payment for a period after a relationship begins, with a paid opt-out, so read the current version first.
What if the first milestone comes back badly? Stop at the boundary and pay for it. A candid conversation and a $1,500 loss in week two beats the same conversation in month five with $18,000 committed and a launch date already announced.
If you would rather have someone technical on your side of the table, that is the work AB7 Solutions does around builds like this: turning a feature document into something that can be priced, writing the milestone and deploy clauses before you fund anything, running the independent review at milestone two, or supplying named engineers who work inside your repository and cloud accounts through contract staffing and staff augmentation. We build applications and APIs outright where that is simpler, and we will say so if your Upwork candidate is fine and only the contract needs fixing. Call +1 321 341 7733, email ab@ab7solutions.com or director@ab7solutions.com, or start at www.ab7solutions.com.
Sources: Upwork User Agreement (not a party to service contracts, no guarantee of users’ services, user responsibility for verification, one account, no password sharing, identity accuracy, Optional Service Contract Terms as a sample only); Upwork Payment Protection (escrow funded before work, $5 milestone minimum, 14-day auto-release, work diary, dispute of the previous week’s hours, exclusion of bonuses, manual time and fixed-price work); Upwork support on the fixed-price dispute process (non-binding mediation, response and acceptance windows, Notice of Non-Resolution, externally purchased arbitration, seven-day filing window); U.S. Copyright Office, Circular 30: Works Made for Hire. Terms verified at time of writing and subject to change. General information, not legal advice.