LFH Lab Start a project
Lab Notes/Building
BUILDINGMAY 2026

One service to rule them all

Why every site I run posts its forms to the same small backend, and what that decision keeps buying me.

Somewhere around the fifth site, I caught myself building a contact form for the fifth time.

Not the HTML. The HTML is twenty lines. The part behind it: where the submission goes, who gets emailed, what happens when that email bounces, how spam gets filtered, where the record lives so I can find it in six months. Each of the first four sites had its own answer. Two used a hosted form service. One posted to a serverless function I'd written in an afternoon and never opened again. One, I'm fairly sure, emailed me from the browser through a plugin I no longer trust.

None of them were broken. All of them were different. Different is what costs you.

One endpoint, every site

Every static site LFH Lab runs now posts its forms to a single service. It's called labcomms, and it's about as unglamorous as software gets: Node and Express, a MongoDB collection per form type, Mailgun for outbound mail. It handles contact forms, quiz submissions, and the assorted "tell me when this ships" boxes every product site accumulates. When a new site launches, adding forms means registering the site in labcomms and pointing the form at it. That's the whole job.

The sites themselves stay static. Eleventy builds them. Nginx serves them off a small Digital Ocean box. There's no server-side code anywhere near a marketing page, with one exception: this endpoint, which all of them share.

What it actually buys

The obvious win is that I write form handling once. Real, but the smallest of the benefits.

The bigger one is that every submission from every site lands in one place, in one shape. When someone fills in the contact form on this site, the same code runs as when someone finishes the free assessment on Leader Ethos or asks a question on MyUptimeBot. One query shows me all of it. One commit changes spam filtering for thirteen sites. When Mailgun changes an API, I fix it in one repo, not seven.

The least obvious win is behavioral. Because adding a form is nearly free, I add forms where I otherwise wouldn't bother. A product page gets a "notify me" box because it costs nothing. A blog post gets a "was this useful?" prompt. Those small collection points are how you find out whether anyone is reading, and they only exist because the price of adding one dropped to zero.

What it costs

A shared service is a shared point of failure. If labcomms goes down, every form on every site fails at once. That's a real risk, and the mitigation is dull: it's monitored (by MyUptimeBot, which I also own, which is the kind of dogfooding that keeps the whole arrangement honest), it has almost no moving parts, and it does exactly one thing. Services that do one thing rarely fail for interesting reasons.

The other cost is discipline. A central service is a magnet for scope. Every time I've thought "labcomms could also handle X," the right answer has been no, roughly nine times out of ten. It handles form submissions. It doesn't send newsletters, run drip campaigns, or manage users. Those live elsewhere and talk to labcomms only when a form is involved.

If you're hiring me

This is the pattern behind most of how I build: find the thing you'll do more than twice, do it once properly, and make the second and third times boring. It isn't clever. In twenty years of engineering it's been the single biggest difference between a portfolio one person can maintain and one that quietly falls apart the first month that person is busy.

A client build gets the same instinct. The parts that will recur get centralized. The parts that won't get built simply and left alone. And the handoff doc includes a line that says, in effect: here is the one place all the forms go, and here's why.

Before you build your next form, go find out where the last four went.

More notes, or the work itself.
Everything here comes from products that are live right now. Read the rest of the notes or go look at the shelf.
All notes The work →