Build a HubSpot alternative

Build a HubSpot alternative as contacts, deals, and a pipeline board. $20–$150 a person a month is rent you can cancel after four days of real deals.

  • getting-started
  • vibe-coding
  • scope

You can build a HubSpot alternative as contacts, deals, and a pipeline board. HubSpot CRM is that product. The catalog line is “Contacts, deals, follow-ups. Leave the marketing empire behind.”

You pay $20–$150 a person a month for it. That is $240–$1,800 a year for every person on the team. The basic replacement is 4 days: contacts, deals, a pipeline board, and notes.

I would ship this if I still rented a CRM for a pipeline I already keep in my head. It is marked Side quest. The verdict on the card is “Build the pipeline you use”.

Last time I wrote about vibe coding your own Loom. That was a teardown. This one is a regular backlog topic. The useful v1 is the deals you already have, not the marketing platform.

What you need to build a HubSpot alternative

The HubSpot CRM page splits the work into three rows.

The first row is the one you want this week. Contacts and companies. Deals with a value, an owner, and a stage. A board you can drag. Notes on the deal.

The second row is 2 weeks. An activity timeline, tasks, duplicate detection, pipeline reports. Those can wait until one real deal already moved from qualified to won.

The third row is 3 months and up. Marketing automation, custom objects, an app marketplace, enrichment. The table labels that row as the part you should skip.

If you tell an agent to “clone HubSpot”, it aims at the third row. Copy the prompt, then pin it to the first one.

Here is the shape of the data. Nothing else has to exist at 4 days.

const company = {
  id: 'co-bootcamp',
  name: 'Bootcamp.dev',
  domain: 'bootcamp.dev',
}

const contact = {
  id: 'ct-ada',
  email: '[email protected]',
  name: 'Ada Rossi',
  companyId: 'co-bootcamp',
}

const deal = {
  id: 'deal-pro-plan',
  title: 'Pro plan, 12 seats',
  companyId: 'co-bootcamp',
  contactId: 'ct-ada',
  stage: 'qualified',
  amountCents: 240000,
  currency: 'USD',
  ownerId: 'U-flavio',
}

const note = {
  id: 'note-call-27-oct',
  dealId: 'deal-pro-plan',
  body: 'Ada wants invoicing on the 1st.',
  authorId: 'U-flavio',
}

Ada is a contact on Bootcamp.dev. The deal sits in qualified at $2,400. You write the note after the call. Later you drag the card to proposal. The board and the deal page have to agree.

SAVE A CONTACT Ada Rossi at Bootcamp.dev Email plus a company domain OPEN A DEAL $2,400, owner, qualified Value stored as 240000 cents DRAG THE STAGE Qualified to proposal One service writes the history Write the note from the call Timeline and tasks wait two weeks
The 4-day v1 is a contact, a deal, a drag, and a note. Marketing automation stays off.

How does HubSpot work

I am describing the catalog’s model here, not reverse-engineering HubSpot. A CRM is a list of people and companies, plus the money you hope to close, plus the next thing you said you would do.

The screens on the page are a dashboard, a contacts directory, a deal pipeline, and a deal detail. For 4 days you can live with the directory, the board, and the deal page. Win rate waits for history, so the dashboard sits on the 2-week row.

The data model is Contact, Company, Deal, Activity, Task, PipelineStage. This week you need Contact, Company, Deal, and PipelineStage. A note can be a thin Activity row. Tasks belong on the 2-week row.

The capability line is Astro, HTMX, and D1. This site is an Astro app on Cloudflare, so that is the path I default to. Node.js plus Astro is the catalog default. Use TanStack Start if React is your weekday language.

Every query is scoped by workspace and role. A guessed deal id from another account returns nothing: no company name, no amount, no 404 that confirms the slug. Exports are admin-only, and each one lands in the audit log.

Who a HubSpot alternative is for

The audience line on the page is specific. A small B2B sales team with one straightforward deal pipeline.

The goal is contacts, company context, deal stage, and a next action in one place you trust. This week, that means one pipeline, one currency, and the deals you already have.

If you need marketing automation, a second custom object for “properties”, or a marketplace of apps, keep paying. The site puts that rebuild at 3 months on purpose.

The same v1 also replaces Attio, Folk, and Copper if what you wanted was a pipeline you own. One focused build covers whichever of those you currently pay for.

A deck you send before the call is DocSend, $65–$180 a month, about 4 hours. The DocSend walkthrough is that post. Build this if the question is “what stage is Ada in”, not “did they open page 7”.

How a HubSpot alternative moves deals

The third mini-prompt on the page is “Stage moves that count themselves”.

One service owns every stage change. The board drag, the dropdown on the deal page, and a later bulk action all call it. No caller writes stage on the deal row by itself.

The service does three things in one transaction: update the stage, append a history row, bump any denormalized column totals. History is deal, old stage, new stage, actor, time. Conversion later reads that log, so a drag that skips it makes the report wrong.

async function moveDeal(db, dealId, newStage, actorId, expectedVersion) {
  return db.transaction(async (tx) => {
    const deal = await tx.getDeal(dealId)
    if (deal.version !== expectedVersion) {
      throw new Error('stale deal')
    }

    await tx.updateDeal(dealId, {
      stage: newStage,
      version: deal.version + 1,
    })

    await tx.insertHistory({
      dealId,
      from: deal.stage,
      to: newStage,
      actorId,
      at: new Date().toISOString(),
    })

    return tx.getDeal(dealId)
  })
}

Two people dragging the same card need a version check. The loser snaps home and refetches. A failed drag has to revert on the board. Optimistic UI is fine if the server result wins.

I would store amountCents as an integer. The other money apps on this site already do that. $2,400.00 is 240000. Stage totals sum integers. You format at the edge.

Contacts and companies

A contact has an email. A company has a domain. Normalize both before you look them up: lowercase, trim, strip www. [email protected] and ACME.com are the same company. [email protected] typed twice is the same person.

The first mini-prompt is “The duplicate detector that asks before it merges”. That work sits on the 2-week row. This week, refuse a silent second contact when the normalized email already exists. Show the match. Let a human decide.

A merge later has to reparent activities, tasks, notes, and deals. Do not auto-merge because two emails share a last name.

Companies are not a free-text field on the contact. If Ada changes jobs, you move the contact. The old company’s open deals stay put until you say otherwise.

What not to build in a HubSpot clone

Leave out marketing automation, customer support, call recording, enrichment, and custom objects.

The non-goal on the page already names those. You are replacing the pipeline you currently rent.

Marketing automation is the trap. Sequences, scoring, landing pages, the form that creates a contact from an ad. That is a second product. Paste the skip row when the agent starts a nurture workflow.

Support tickets belong in Intercom, $74–$139 a person a month, about 4 days for a help button and a shared inbox. The Intercom teardown is routing, the customer graph, and product tours.

If the agent starts an app marketplace or an enrich button, stop it and paste the non-goal again.

4-DAY V1 Contacts and companies Deals on a drag board Notes and stage history SKIP THIS HALF Marketing automation Custom objects and enrichment App marketplace
Ship the 4-day pipeline. Leave automation, objects, and the marketplace on the skip row.

HubSpot alternative or Pipedrive

Pipedrive is the same job with a stricter first row. $24–$79 a person a month. 3 days for a drag-and-drop pipeline, deal cards, and a next action. The verdict is “One pipeline is enough”.

Pipedrive’s card requires a next activity on every live deal. Completing a call forks into schedule-the-next or close. HubSpot’s first row is looser: contacts, deals, board, notes. If your pain is forgotten follow-ups, start on the Pipedrive card. If your pain is “I cannot see the board we already have”, start here.

I would not put customer requests in this CRM. Canny is $79–$99 a month, about 10 hours. The Canny walkthrough is search, one vote, and a public status.

Invoices after you win belong in FreshBooks, $23–$60 a month, about 10 hours for clients, invoices, and a PDF.

The per-seat post is why five HubSpot seats on the high plan is $9,000 a year. The scope post is the same three-row table if you want the habit, not just this card.

The 2-week row, after one real pipeline

Use the board for two weeks as the real pipeline, not as a demo. Then look at the second estimate.

An append-only activity timeline: notes, calls, meetings, email summaries, stage changes. Corrections keep the original text, the editor, the reason, and the time. System rows cannot be edited.

Tasks with an owner, a due date, and an overdue view. Duplicate suggestions at create and on CSV import. Pipeline value, stage conversion, win rate, and a CSV an admin can export.

BCC capture is a mini-prompt on that row. A magic address files a message onto the matched contact. Deduplicate on Message-ID. Unknown senders sit in a queue.

The catalog says 2 weeks for that row. Stop there. The prompt post is the extra line that says do not build marketing automation.

Host it, import real deals, cancel

The product pages put hosting this way: a focused replacement costs your build time plus close-to-zero hosting.

This one wants Astro, HTMX, and D1, because that is the stack on the card. There is a table for deals and history, so take a backup before you delete the paid account.

Put the board on a hostname you already own, crm.flaviocopes.com. Import the contacts you already email. Open the five deals that are live this month. Drag one. Write the note from yesterday’s call. Confirm the board, the deal page, and the history row all show the same stage.

If you miss tasks or a win-rate chart, add them from the 2-week row.

Then cancel HubSpot CRM, or Attio, or Folk, or Copper, whichever one you pay for.

I would not start here as a first vibe-coded app. The first-project post still points at a tonight card. This is the side quest after you have shipped one small tool.

Start now

Go to Build your own HubSpot CRM. Copy the Astro prompt, or TanStack Start if that is what you write.

Tell the agent the first estimate only: contacts, deals, pipeline board, notes. Four days.

Import the deals you already have. Drag one to the next stage this week.

Keep reading

Read all articles →