The first thing we did was build the wrong thing.

It was August. We had been running on a stitched-together combination of HubSpot Starter, a Google Sheet that one person was quietly responsible for, and a Notion database that everyone agreed was the source of truth even though nobody could explain why. Three places, three slightly different versions of who our customers were, and a growing suspicion that we were going to get caught.

The decision to build came on a Tuesday. HubSpot raised its prices, the Notion database broke for the fourth time, and someone on the team said the words out loud: “We could just build this.” Eight hours later we had a wireframe. Six weeks later we had something people were logging into. And six months later we had a much clearer view of the question we should have asked before we wrote a single line of code.

The question was not build or buy. We treated that as the decision, and it was the wrong decision to be making.

The question we should have been asking

The standard build-versus-buy framework treats a CRM as a single thing. It is not. A CRM is four or five distinct systems held together by convention:

  1. A contact database: who is this person, and what do we know about them.
  2. A timeline log: what has happened with this person, and when.
  3. A pipeline view: where a given deal sits in our process.
  4. A task system: what needs to happen next, and who owns it.
  5. A reporting layer: the shape of all of it in aggregate.

Off-the-shelf CRMs ship all five tightly coupled, and the pitch is that the coupling is the value. Everything connected, one source of truth, calm Mondays. For a large sales organization, that pitch is largely true. For a small team, the reality is that you are paying fifty dollars per seat per month for four systems you barely touch in order to reach the one you actually need.

So the question is not whether to build a CRM. The question is which of those five layers your situation actually requires you to own, and which you should keep renting. We did not ask it that way. We asked “should we build a CRM,” answered yes, and then spent three weeks building a small, sad imitation of HubSpot.

Three false starts

The first version was a CRM-shaped clone of the tool we were leaving. It had a pipeline, deal stages, a dashboard. It also had nobody using it, because it did everything HubSpot did except worse, and HubSpot at least had a mobile app and a decade of polish.

The second version overcorrected. We rebuilt it as a Notion database with extra steps: flexible, structureless, and immediately back to the exact ambiguity we were trying to escape. If your internal tool can become anything, it will, and then it is a Notion database again, only one you now have to maintain yourself.

The third version was so spartan that it stored contacts and nothing else. Technically correct, genuinely used by no one, because a list of names with no context is a phone book, and we already had several of those.

The fourth version is the one we still run. It came from finally asking the right question, and from accepting that the first three weeks of work were tuition rather than progress.

What we actually built

We built two of the five layers. Just two.

We built the contact database, because we needed it to talk to our other systems: billing, support, and outreach via Apollo for sequences and Mailgun for transactional sends. No off-the-shelf tool stitched those specific sources together the way we needed, and the stitching was most of the value. The database itself runs on Postgres hosted through Supabase, which also handles auth via Supabase Auth, so we did not have to cobble together a separate login layer using Clerk or Auth0. That decision alone saved a week of setup.

We also built the timeline log, because the worth of a CRM compounds when you can see the whole history of a relationship in one place. Every rented tool we tried got this almost right and never quite right enough.

Everything else, we kept buying. Pipeline view? A basic board inside Linear, because that is where the team already works. Tasks? The same board. Reporting? A weekly query against the Postgres database run through Metabase, pasted into a slide. Clean enough. None of those three needed to be ours. Owning them would have meant three more things to maintain in exchange for nothing.

The result is a CRM that nobody outside the company would recognize as a CRM. It does one job well, and it does not try to do four other jobs poorly.

That is the whole trick, and it took three failed builds to see it. The tool is small on purpose. Small the way a good knife is small.

What it cost

Honest numbers, because the math is the only part of this that transfers.

Time. About six weeks of one engineer’s part-time attention to reach a first version people used. Another four weeks, spread across the following six months, spent fixing the seams we only found by using it. Call it ten engineer-weeks before the tool stopped actively annoying anyone.

Money. Roughly eighty dollars a month in hosting and database costs, all in. Supabase’s Pro plan covers the Postgres instance and auth at that range for our data volume.

What it replaced. Around three hundred and forty dollars a month in CRM software, plus an estimated four hours a week of cleanup and reconciliation across the old three-system patchwork. That reconciliation time was the hidden cost nobody had been counting, and it turned out to be larger than the subscription.

On paper that is a clear win. But the paper hides something. The math only works because we are a software team building a tool we will use ourselves. The engineer-weeks were real cost, and we could absorb them because building is what we already do. If you would need to hire someone to do this, recompute everything. The equation can flip fast, and it flips against building more often than the build-it-yourself crowd will admit.

What we wish we had known

A few things, six months in.

The hard part was never the building. Deciding what to leave out proved harder than anything on the technical side. Every person on the team wanted one feature, and each request was reasonable on its own. We added most of them. We removed most of them three months later. The clearest sign a CRM is wrong is when nobody opens it. The second-clearest sign is when everybody opens it and then complains about it for half an hour.

An internal tool needs an owner. Not a maintainer in the sense of someone who fixes bugs. An owner in the sense of someone with the authority to say no to features. Without that person, an internal tool collects scope the way a hull collects barnacles: slowly, and then alarmingly.

The real risk is drift, not downtime. A rented tool like HubSpot or Salesforce has an entire company keeping it current with the world. New integrations, new fields, new compliance requirements. Ours has us, and we have other jobs. Six months in, it already shows its age in small ways. We have decided to live with that. You might not want to, and that is a legitimate reason to keep renting.

You become a software vendor to yourselves. The tool has bugs. People file them in one specific Slack channel. Releases happen. Somebody triages. The cost of running an internal tool is not zero and never becomes zero. It just becomes invisible, which is worse, because invisible costs do not get budgeted and therefore do not get defended.

When this works, and when it does not

For us, the build made sense because four things were all true at once. The team was small, under fifteen people. The workflow was specific enough that most standard CRM features simply did not apply. The people building the tool were the people using it. And the underlying contact database had to integrate with our own custom systems regardless, so some of the work was unavoidable either way.

Change any one of those and the answer changes. For a fifty-person sales team running a conventional B2B pipeline, none of this applies. Buy HubSpot or Salesforce, hire an administrator to run it well, and get back to selling. That is not a compromise. It would have been the correct call for us too if our situation had been even slightly more ordinary.

The build path is narrower than the build-everything crowd wants to admit, and wider than the buy-everything crowd will tell you. The work is in locating, honestly, which side of that line your specific situation falls on, and then being willing to be wrong about it later.

What this experience taught us, in retrospect

Three things.

Build less. Two layers, not five. We burned weeks on a reporting interface that turned out to be one weekly Metabase query a person could run in under a minute.

Name the owner before you write the first line of code. Without someone holding authority over scope, every feature request quietly becomes a small political negotiation, and small political negotiations are how calm teams stop being calm.

Treat the decision as temporary. This is not a monument. Every six months the inputs move: the team grows, vendor pricing shifts, the off-the-shelf tools get better or worse, your own needs change shape. Put a recurring calendar reminder to rerun the math, and mean it. Be genuinely willing to delete the thing and go back to renting.

We are due for that review in about four weeks. The team is genuinely uncertain what we will decide. That uncertainty is not a failure of planning. It is the correct posture toward a tool: useful for now, kept only as long as the numbers still say so.