billable.dev

How to Estimate a Software Project as a Freelancer

By Mark Fulton · 2026-10-01 · 11 min read

How to Estimate a Software Project as a Freelancer

To estimate a software project as a freelancer, list every feature, split each into tasks of a day or less, give every task a best, likely and worst-case hour count, and turn those three numbers into one weighted figure with (best + 4 x likely + worst) / 6. Add the weighted hours up, add a written risk buffer on top, multiply by your rate, and send the client a range with your assumptions attached. Once they pick a number, the approved estimate becomes a fixed quote and a deposit invoice. The method below is worked through on a fictional 12-task SaaS dashboard, with every figure checked, so you can copy the structure and swap in your own tasks.

Why do freelance estimates run over?

Almost every overrun traces back to the same few causes, and none of them is "I am bad at coding."

You estimate the happy path. When someone asks "how long for user login," you picture the version where nothing goes wrong. You do not picture the password reset flow, the email provider quirk, the OAuth callback that behaves differently in production. This habit has a name, the planning fallacy, first described by Daniel Kahneman and Amos Tversky: people underestimate the time, cost and risk of what they are about to do, even when they have been burned before.

You give one number. A single figure hides how unsure you are. "Ten days" and "ten to fifteen days" are different statements, and the client deserves to know which one you mean. Jacob Kaplan-Moss makes this point well in his write-up of his own estimation technique: an estimate should capture both time and uncertainty, because a bare time implies a certainty nobody has.

You estimate big lumps. "Build the admin panel" is not a task. It is a pile of tasks you have not looked at yet. The bigger the lump, the more unknowns hide inside it.

You forget the work around the work. Testing, bug fixes after review, deployment, handover notes, and the three calls where the client changes their mind about a button. None of that is code, all of it is billable, and it is the first thing missing from a quick estimate.

The estimate never became a contract. Even a decent estimate fails if it lives in a chat message with no assumptions attached. When the client adds a feature, there is nothing to point at. That is a scope creep problem, and it starts at the estimate, not at the change request.

The fix is a repeatable process. Six steps, same order every time.

How do you break a project into estimable tasks?

Start with a feature list in the client's words, then break every feature down until each task is something you could finish in one working day or less.

A practical rule: if you cannot say what "done" looks like for a task in one sentence, it is too big. Split it.

Here is a feature list for a fictional project, an analytics dashboard sold as a subscription product:

  1. Authentication and accounts
  2. Database schema and API scaffold
  3. One data connector (OAuth to a third-party source)
  4. Dashboard layout and navigation
  5. Four chart components
  6. Filters and date ranges
  7. CSV export
  8. Stripe subscription billing
  9. Email notifications
  10. Admin panel
  11. QA and bug fixing
  12. Deployment and handover documentation

Notice items 11 and 12. They are tasks, with hours attached, not overhead you absorb. Put QA and handover on the list every time. If the client has not seen them as line items, they will assume they are free.

If the project is too vague to break down at all, stop estimating. A vague brief is a signal to sell a small paid discovery step first. That is covered in the paid discovery phase for developers, and it is cheaper for both sides than guessing at a number you will later regret.

What is a three-point estimate and how do you calculate it?

A three-point estimate gives each task three numbers instead of one: a best case (a), a most likely case (m) and a worst case (b). You then combine them into an expected value with the PERT weighting. The three-point estimation method defines the expected value as E = (a + 4m + b) / 6 and a standard deviation as SD = (b - a) / 6, where E is a weighted average that accounts for both the optimistic and pessimistic figures and SD measures the uncertainty in the estimate.

The weighting matters because software skews late. Your worst case is usually much further from "likely" than your best case is, so the weighted figure lands above your gut feeling. That gap is the whole point. It is the work your gut forgot.

How to fill the three columns honestly:

  • Best (a): everything works first time, the library docs are right, the client answers in an hour. Not a fantasy, but not what you expect.
  • Likely (m): what you would bet on. Include normal friction.
  • Worst (b): not the apocalypse, but the realistic bad day. The API is flaky, the design needs a rework, a dependency breaks. Think "one in ten," not "meteor."

Worked example: a 12-task estimate (fictional)

This is a made-up project for illustration. The hours are invented to show the arithmetic, not benchmarks for what these tasks take in your stack.

# Task Best Likely Worst Weighted (E)
1 Authentication and accounts 6 10 20 11.00
2 Database schema and API scaffold 8 12 22 13.00
3 Data connector (OAuth) 10 16 36 18.33
4 Dashboard layout and navigation 6 9 15 9.50
5 Four chart components 10 14 26 15.33
6 Filters and date ranges 5 8 16 8.83
7 CSV export 3 5 10 5.50
8 Stripe subscription billing 8 14 30 15.67
9 Email notifications 4 6 12 6.67
10 Admin panel 5 8 14 8.50
11 QA and bug fixing 8 12 24 13.33
12 Deployment and handover docs 4 6 10 6.33
Total 77 120 235 132.00

Check one row by hand. Task 3: (10 + 4 x 16 + 36) / 6 = (10 + 64 + 36) / 6 = 110 / 6 = 18.33. Check the total the same way: (77 + 4 x 120 + 235) / 6 = (77 + 480 + 235) / 6 = 792 / 6 = 132.

Look at what the table tells you. Adding up only the "likely" column gives 120 hours. The weighted total is 132. The 12-hour difference is the cost of the risk that your gut left out. If you had quoted 120 and the real job landed on the weighted figure, you would have worked 12 hours for free before a single surprise showed up.

The best-case total of 77 hours and worst-case total of 235 hours are not prices. Every task will not hit its worst case at once. Treat them as the outer edges of what could happen, and the weighted total as the number you plan around.

If you want a single measure of how uncertain the whole project is, take each task's (b - a) value, square them, add them up, take the square root and divide by 6. Here the squares sum to 2,496, the square root is about 49.96, and the project SD comes to about 8.3 hours. That assumes task errors are independent, which is generous, so use it as a rough sense of scale and not a guarantee.

Two cautions. First, use real working hours, not idealized ones. Kaplan-Moss makes the same point in his piece: a "small" task in his scale really does take about half a day once the normal interruptions of a workday are counted. Second, pick a scale and keep it. The value of tracking estimates against actuals only appears after a handful of projects.

How much buffer should a solo developer add?

Add a separate, named buffer on top of the weighted total, sized to the risk that the task list cannot see. The three-point math already covers uncertainty inside each task. The buffer covers what is outside the list: client delays, a requirement nobody mentioned, a tool that changes under you.

There is no universal percentage, and anyone who claims one is guessing. A workable way to choose is to look at the project, not a formula:

  • Known client, clear brief, familiar stack: a small buffer, around 10 percent.
  • New client or loose brief: around 15 to 20 percent.
  • Unfamiliar stack, third-party integrations, or a client who changes direction often: 25 percent or more, or a paid discovery step before you commit.

Treat those numbers as starting points, not research findings. The principle is what matters: the buffer is explicit, written down, and tied to a stated reason.

For the fictional dashboard, take a 15 percent buffer because the data connector depends on someone else's API:

  • Weighted hours: 132
  • Buffer at 15 percent: 132 x 0.15 = 19.8 hours
  • Buffered total: 132 + 19.8 = 151.8, call it 152 hours

Now price it. At a rate of $95 an hour:

Scenario Hours Calculation Price
Likely column only (do not quote this) 120 120 x $95 $11,400
Weighted estimate 132 132 x $95 $12,540
Weighted plus 15% buffer 152 152 x $95 $14,440

The range you present is $12,540 to $14,440. Not $11,400. If you need a refresher on picking the rate itself, see freelance developer hourly rates.

How do you present the estimate so it becomes a signed quote?

Send a range, not a single number, and attach the assumptions that make the range true. Then ask the client to choose a scope and a price in writing.

A range is honest, and it gives the client something to negotiate with that is not your rate. If the budget is closer to $12,540, the conversation becomes "what do we cut or defer," which is the conversation you want. If you send $13,000 flat, the conversation becomes "can you do it for $10,000," which is the one you do not.

The assumptions are what turn a range into a boundary. Here is a block you can paste into the estimate and edit:

ASSUMPTIONS
- Estimate covers the 12 tasks listed above and nothing else.
- Includes two rounds of revisions on the dashboard layout.
- One data connector is included. Each additional connector is a change order.
- Client provides API credentials and sample data within 3 business days of kickoff.
- Client feedback is returned within 2 business days. Delays move the schedule.
- Hosting, third-party fees and stock assets are paid by the client.
- Estimate valid for 30 days from the date above.
- Work outside this list is quoted separately before it starts.

Then convert the estimate into money documents, in this order:

  1. Estimate (the range plus assumptions). Not binding. It is a basis for a decision.
  2. Quote (one chosen price and scope, signed). This is the fixed price for the agreed list. The differences between these documents are laid out in proforma invoice vs invoice vs quote vs estimate.
  3. Deposit invoice. On a $14,440 fixed quote, a 30 percent deposit is $4,332 (14,440 x 0.30). How big the deposit should be is its own question, covered in how much deposit to charge for freelance dev work.
  4. Milestone or final invoices for the remainder.

Whether to quote fixed price or bill hourly against the estimate is a separate decision with real trade-offs, and hourly vs fixed price walks through them. If you go fixed, the buffer is what pays for your risk, so do not give it away in the first round of negotiation.

When the quote is signed, you generate the deposit invoice. The free invoice generator runs entirely in your browser, with no account. If you want the approved estimate turned into the invoice for you, Billable Pro is $4 a month billed $24 per six months, or $79 for a lifetime license.

FAQ

Should I charge for writing an estimate?

For a small, well-defined job, a free estimate is a normal cost of selling. For anything where you must dig into unclear requirements, existing code or integrations to produce a number, charge for it. A paid discovery step produces a better estimate, filters out people who only want a number to shop around, and the fee can be credited against the project if they sign. See the paid discovery phase.

Should I give a range or a single number?

Give a range while scope is still being shaped, and a single number once the client has chosen a scope and signed. A range shows your uncertainty honestly. A single number is the right output of a signed quote, not of an early estimate.

How do I estimate work in an unfamiliar stack?

Widen the worst-case column, and say so. Unfamiliar tools make your worst case much further from your likely case, so the weighted figure rises on its own. For anything central to the project, build a tiny throwaway spike first, a few hours to prove the hardest integration works, and estimate the rest after you have seen it. Charge for the spike, or fold it into a paid discovery step. A larger buffer, 25 percent or more, is also reasonable until you have shipped something in that stack.

What if the estimate is wrong halfway through?

Tell the client as soon as you see it, not at the end. Compare actual hours so far against the weighted figures for the tasks you have finished. If you are over because the client changed the work, that is a change order, not an estimate error. If you are over because you misjudged, decide whether the buffer absorbs it. If it does not, raise it early with the facts, offer to cut or defer scope to hold the price, and learn from the gap so the next estimate is better. The change order post has a reply script for the first case.

This post is general information about estimating and pricing work, not legal or financial advice. Have a contract reviewed before relying on any clause.


Billable is a free, client-side invoice generator for developers. Your data stays in your browser.