DEV Community

Cover image for I built a freelance rate calculator with Next.js
MIKE
MIKE

Posted on

I built a freelance rate calculator with Next.js

Here's the maths most calculators get wrong

Most freelance rate calculators are wrong. Not buggy — conceptually wrong. They take your income goal, divide by hours, and hand you a number that will quietly lose you money all year.

I got tired of explaining the correct calculation to freelancer friends, so I built a tool that does it properly. Here's the logic behind it, and a bit about how I built it.

The flawed formula

The typical calculator does this:

hourly_rate = annual_income_goal / annual_hours_worked
Enter fullscreen mode Exit fullscreen mode

So if you want $80,000 and work 2,080 hours a year (40 × 52), it tells you to charge ~$38/hr.

This is wrong in three separate ways.

Fix 1: Tax is not optional

Your income goal is a net number — what you want to keep. But you're taxed on gross. So the first correction is grossing up:

const grossIncome = netTarget / (1 - taxRate);
// $80,000 / (1 - 0.28) = $111,111
Enter fullscreen mode Exit fullscreen mode

That's already a $31,000 gap the naive formula ignores.

Fix 2: You don't bill every hour you work

This is the big one. Freelancers bill roughly 55–65% of their working hours. The rest is admin, proposals, invoicing, sales calls, and learning.

const totalHours = weeksWorked * hoursPerWeek;        // 46 * 40 = 1840
const billableHours = totalHours * billableRatio;     // 1840 * 0.6 = 1104
Enter fullscreen mode Exit fullscreen mode

So your real billable capacity isn't 2,080 hours. It's closer to 1,104. Pricing on the wrong denominator is how people end up working 50-hour weeks and still missing their income target.

Fix 3: Business expenses come out of gross

Software, hardware, insurance, courses — all real costs that need covering before you pay yourself:

const totalNeeded = grossIncome + annualExpenses;
Enter fullscreen mode Exit fullscreen mode

The corrected formula

Putting it together:

function minimumRate({ netTarget, taxRate, expenses, weeks, hoursPerWeek, billableRatio }) {
  const gross = netTarget / (1 - taxRate);
  const totalNeeded = gross + expenses;
  const billableHours = weeks * hoursPerWeek * billableRatio;
  return totalNeeded / billableHours;
}

minimumRate({
  netTarget: 80000,
  taxRate: 0.28,
  expenses: 8000,
  weeks: 46,
  hoursPerWeek: 40,
  billableRatio: 0.6
});
// ≈ $107/hr — not $38/hr
Enter fullscreen mode Exit fullscreen mode

That's a 2.8x difference from the naive calculation. On a full year, the gap between charging $38 and $107 is enormous.

How I built it

The tool is a Next.js 14 app (App Router) deployed on Vercel. The calculator itself is a single client component using useState for the inputs and useMemo for the derived rate — no backend needed, all the maths runs in the browser.

The interesting architecture decision was programmatic SEO. Rather than one page, I generate static pages for every profession × country combination using generateStaticParams:

export async function generateStaticParams() {
  return COUNTRIES.flatMap(country =>
    PROFESSIONS.map(profession => ({ country, profession }))
  );
}
Enter fullscreen mode Exit fullscreen mode

That turns 8 professions and 6 countries into 48 statically-rendered pages, each targeting a specific long-tail search like "freelance developer rate in Australia" — all built at deploy time, all served from the edge.

Market benchmark data lives in plain JSON objects keyed by profession, with a currency multiplier applied per country. No database, no CMS — just static data and static rendering, which keeps it fast and free to host.

Try it

The live tool is at freelancecalculator.net — free, no signup. Set your currency, enter your numbers, and it shows your minimum rate, a recommended rate with a 20% buffer, and how you compare to market benchmarks.

If you're a freelance dev and you've never run your rate through the corrected formula, it's worth 60 seconds. Your number might be higher than you think.

Top comments (0)