What we’re built on.

Every company and open-source project Dice runs on, and what each one actually does here. A dependency nobody can explain the job of is a dependency worth removing, so this list is the whole list.

The application

Next.js

The framework everything runs on.

App Router with server components. The marketing pages and the dashboard are rendered on the server, so a page of scoring evidence arrives as HTML rather than as a spinner followed by three fetches.

React

The interactive layer.

Only what genuinely needs interaction ships JavaScript — the opportunity filters, the pipeline runner, the preview cards. Everything else stays a server component and costs the browser nothing.

TypeScript

Types on every boundary.

Scoring weights, database rows, and API responses share one set of types. Change how an opportunity is scored and the build fails, rather than a customer's ranked list quietly changing meaning.

Tailwind CSS

The token layer and every style.

One set of tokens defines the palette, radii, and shadows for both themes. Nothing hardcodes a colour, which is why dark mode is a variable swap instead of a second stylesheet.

Vercel

Hosting and the CDN in front of it.

Runs the rendered pages and caches them at the edge. Preview deployments mean a change to the scoring copy can be read in context before it reaches anyone.

Data

Supabase

Postgres, auth, and row-level security.

Every table is scoped to a workspace by a policy inside the database, not by a WHERE clause someone has to remember. A query that forgets the workspace returns nothing instead of returning someone else's opportunities.

PostgreSQL

The database underneath it.

Candidates, enrichments, opportunities, publishers, and contacts are genuinely relational, and ranking is a query over them. Keeping the evidence in a real database is what makes a result inspectable months later.

The pipeline

Trigger.dev

Runs the long jobs.

Discovery, enrichment, qualification, and contact discovery outlive any HTTP request. They run as durable tasks that survive a deploy and retry a flaky provider instead of losing an hour of work.

Firecrawl

Fetches and reads the actual page.

Dice judges an article by its content rather than its title, which means something has to fetch the page and turn it into clean text first. This is the step most tools skip.

OpenAI

Reads the article and rates the fit.

Content relevance, placement suitability, and the competitor gap come from a model that has read the page. The weights that turn those into a score are ours, deterministic, and published on the home page.

Hunter

Supplements contact discovery.

Public author bylines and contact pages come first. Hunter runs only after a page is qualified, so credits are never spent on a candidate that the hard checks were going to reject anyway.

Money and mail

Polar

Checkout and subscriptions.

Handles the paid trial and the monthly plan, and tells the app what someone is entitled to through a webhook. Access is derived from that, never from a flag set by hand.

Resend

Sends the transactional mail.

Sign-in links, receipts, and the notification that a pipeline run has finished. A plain API and sane deliverability defaults, which is what keeps a small sender out of the spam folder.

Gmail API

Connects a Google mailbox.

Outreach goes out from your own address, not from a shared pool. OAuth means the connection can be revoked from your Google account at any time, without going through us.

Microsoft Graph

Connects an Outlook mailbox.

The same arrangement for Microsoft 365 and Outlook accounts, through MSAL. IMAP and SMTP remain available for everything neither provider covers.

Toolchain

Node.js

The runtime.

Server rendering, the API routes, and the background tasks all run on it — one language across the request path and the pipeline.

pnpm

Installs the dependencies.

Strict by default: a package you did not declare is a package you cannot import, which catches a whole class of “works on my machine” before it ships.

Zod

Validates what crosses a boundary.

Model output, webhook payloads, and request bodies are parsed rather than trusted. A malformed provider response fails at the edge with a readable error instead of becoming a null halfway through a pipeline run.

Vitest

Runs the tests.

The scoring, ranking, and hard-check logic are pure functions with unit tests, so the numbers on this site can be derived from the same code that produces them in the product.

ESLint

Keeps the codebase consistent.

Rules for React and Next.js specifically — the ones that catch a client component that did not need to be one, or a state update that will cascade.

Lucide

Every icon on the site.

One consistent stroke weight across the marketing pages and the dashboard, tree-shaken so a page ships only the icons it draws.

Colours

One token layer, two themes. Every swatch below paints itself from the same custom property the app uses, so this page always shows the palette you are actually looking at.

Background--backgroundthe page, everywhere
Foreground--foregroundbody text and headings
Subtle--subtlealternating sections and hover fills
Raised--raisedcards and anything lifted off the page
Muted--mutedsecondary prose
Faint--faintlabels, captions, metadata
Border--borderhairlines between things
Border strong--border-strongthe edge of a card
Primary--primaryactions, links, and where you are
Primary subtle--primary-subtletinted fills behind primary
Success--successverified, complete, passing
Warning--warningaccept-all, needs a look
Danger--dangerrejected and failed

Set in the system UI stack for everything readable, and in Pixelify Sans for the wordmark at the bottom of the page. Self-hosted, so no third party learns which pages you read.

Logos are each vendor’s own and belong to them. Their appearance here records what Dice is built with, not any endorsement by them.