The $4,200 contact form: what a custom backend actually cost us
March 28, 2026 · 8 min read
A founder friend sent me a Slack message last November: "how much can a contact form really cost? I'll just build it myself."
He did. I told him to keep the receipts.
A year later we sat down with a spreadsheet and added everything up. The number surprised both of us. Not because it was huge — it wasn't, not by startup standards — but because almost none of it was visible when he made the call.
Here is what a "free" contact form actually cost his two-person company in twelve months.
The invoice nobody shows you
| Line item | What it was | Cost |
|---|---|---|
| Initial build (dev time) | 11 hours at an internal rate of $120 | $1,320 |
| VPS (2GB, 1 vCPU) | $12/mo for a dedicated endpoint box | $144 |
| Mailgun | Transactional email, ~900 sends/mo | $180 |
| Domain + wildcard TLS | Separate forms. subdomain |
$48 |
| Monitoring (Better Stack) | Uptime + on-call alerts | $120 |
| CAPTCHA fees | hCaptcha Pro after the free tier blew up | $108 |
| Security patch work | Two CVEs, node upgrades, a dependabot avalanche | $540 |
| The 3 a.m. outage | Mailgun suspended for a policy flag, 4 hours of debugging | $480 |
| The spam incident | 40k submissions in one night, cleanup + filtering rewrite | $720 |
| Post-mortem + docs | The "we should write this down" day | $360 |
| Total | $4,020 |
I rounded up to $4,200 in the title because we forgot a few Stripe-paid SaaS tools and one afternoon spent on a GDPR data-export request. Close enough.
The numbers that didn't make the spreadsheet
Some costs refused to be counted. They still showed up.
Context switching. Every time a user emailed "your form is broken," someone dropped what they were doing. Average interruption: 18 minutes. Multiply by 31 reports across the year. That's nine-and-a-half hours of lost focus nobody billed for.
The Sunday evening doom scroll. You know the one. Where you check Grafana from the couch because you just pushed a dependency update and you're not sure nothing broke. Hard to put a dollar on it, but it was real.
The opportunity cost. Eleven hours on the initial build is also eleven hours not spent on the product. For a two-person team, that's a sprint.
"But you could have just used a free tier"
Sure. We did, at first. Here's the problem with free tiers on infra you own: they're free until you succeed.
The first spam wave is where most indie builds crack. You set up a rule, it holds for a week, the bots adapt, you set up another rule, you start second-guessing your regex, and at some point you realize you're building a spam detection company instead of the thing you actually sell.
Our friend's words: "I became the on-call engineer for a form that sends to one inbox."
What we're doing now
He switched to FormTo in January. Not because I begged him. Because he priced his own time at $0 and still couldn't make the DIY math work.
Here's the after picture:
| Thing | Before | After |
|---|---|---|
| Monthly bill | $47 + his time | $29 |
| Time spent on forms | ~3h/month | ~0 |
| 3 a.m. alerts last quarter | 2 | 0 |
| Webhook to their CRM | Custom glue code | Paste URL, done |
| Spam reaching the inbox | ~40/week | ~1/week |
He told me the real unlock wasn't the money. It was the line on his to-do list that finally got crossed off and stayed crossed off.
When rolling your own still makes sense
I'm not going to pretend hosted endpoints are the right call for everyone. Build it yourself if:
- You have strict data residency rules a vendor can't meet
- You're already running the infra and the marginal cost is genuinely zero
- The form is the product (you're building Typeform, hi)
- You enjoy it, and your time is genuinely worth zero on weekends
For every other case — portfolios, landing pages, SaaS marketing sites, agencies shipping client work, indie hackers trying to launch — the math is not close.
The thing I wish someone had told him
You don't notice the cost of a custom form backend in month one. You notice it in month eight, when you're writing a retry policy for a webhook that was supposed to take an afternoon, and you look up and realize you've spent a weekend on a feature that should have cost $29.
Pick your battles. A contact form is not one of them.
If you want to skip the spreadsheet lesson, grab a form slug and paste it into your <form action="...">. Ninety seconds, no VPS, no Mailgun, no 3 a.m. pages.
Or if you're a "read the docs first" type, the docs are here. No signup required.
More posts