Skip to Content
CoursesGTM Engineering02 The data model

The Data Model: Rows, Columns, Actions

Outcome: a paper sketch of your workflow — one row grain, a named column per step, and each column marked free, cheap or expensive — before you build anything.

Surface
App and MCP server
Level
Beginner
Uses
Tables (no enrichment run yet)
Credits
0
Prerequisite
Lesson 01's four-question table

Everything is a table

Sourcing tools, enrichment vendors and sequencers all describe themselves differently, but underneath there is one structure and it has three parts.

PartWhat it isExample
RowOne thing you are working. The grain of the dataset.One company. One person. One job post.
ColumnOne fact about that thing, or one step that produces a fact.domain, employee_count, work_email, score
ActionThe thing that fills a column. Runs per row, bills per row.enrich_organization, find_work_email, an AI prompt

Once you see a workflow this way, most build questions answer themselves. “Where do I put the tech stack check?” is a column question. “Why did this cost so much?” is an actions-times-rows question. “Why are there duplicates?” is a grain question.

Tables is the reference for the structure; Actions is the reference for what can fill a column.


Choosing the grain

The single most consequential decision in a build is what one row represents. Get it wrong and every later stage inherits the mistake.

Company-grain

One row per company. Use when the decision you are making is about the account: is this in market, does it fit, is it worth working.

Person columns do not belong here. The moment you want three contacts per company, a company-grain table forces you into contact_1_email, contact_2_email — the shape that breaks every export.

Person-grain

One row per human. Use when the output is outreach. Company facts get carried along as columns, repeated across the people at that company. That repetition is fine and normal.

Event-grain

One row per occurrence — a job post, a funding round, a LinkedIn post, a form fill. Use when the same company can legitimately appear many times and each occurrence is separately actionable.

The standard mistake is starting person-grain because outreach is the goal. It means you pay to find people at companies you would have disqualified, which is exactly the ordering lesson 06 tells you to avoid.

Most real pipelines are two tables, not one: a company-grain table that qualifies, and a person-grain table built only from the survivors. Splitting them is what makes the qualification stage cheap.


Columns have a price

A column is not a field in a form. It is a per-row cost, and the total is trivially predictable once you write it down.

Column typeCost per rowExamples
Free0Formulas, text you typed, filters, conditional logic
CheapFractions of a credit to ~1Company enrichment, tech stack, headcount, job listings
Expensive~1 and up, often severalPerson-level contact data, mobile numbers, AI research over a page

Write your run cost as rows × sum(column costs) before you build. A 2,000-row table with six one-credit columns is a 12,000-credit run whether or not you intended it. See Credits for exact per-action pricing.


Worked example

Continuing the developer-tool build from lesson 01, on paper:

Table A — company grain

ColumnTypeCost
company_name, domainSourcecheap
employee_count, countryEnrichcheap
ci_toolTech stackcheap
infra_roles_30dJob listingscheap
fit_scoreFormulafree
qualifiedFilter on fit_scorefree

Table B — person grain, built only from qualified = true

ColumnTypeCost
name, title, linkedin_urlFind peoplecheap
work_emailWaterfallexpensive
email_statusVerifycheap
opening_lineAI over Table A’s evidenceexpensive

Two tables, ten columns, and the expensive four run against a fraction of the rows. That is the whole design, and it fits on an index card.


Do this now

  1. Take lesson 01’s four-question table. Decide the grain of your final output — almost always person or event.
  2. Write the columns for that output table, one line each, in the order they must run.
  3. Mark every column free, cheap or expensive.
  4. Draw a line above the first expensive column. Everything above the line is qualification; everything below is execution.
  5. If any cheap column sits below the line, move it up. If the qualification half has fewer than three columns, your gate is too weak — add a criterion.
  6. Split anything company-level above the line into its own table.

Check your work

  • You can state in one sentence what a single row is
  • No column is a list crammed into a cell (contact_1, contact_2)
  • Every expensive column sits below the qualification line
  • You have a written rows × cost estimate for one run

Where this breaks

Mixed grain is the failure that survives longest before it hurts. A table where some rows are companies and some are people looks fine in the app, exports as garbage, dedupes incorrectly, and makes every count you report wrong. If you cannot answer “what is one row?” without saying “it depends,” stop and split the table before adding another column.


Further automation

A table designed this way re-runs cleanly: the qualification half is cheap enough to refresh weekly, and the execution half only runs for rows that newly crossed the line. Lesson 07 covers the dedupe and cadence rules that keep that re-run from re-billing you for rows you already paid for.


Next lesson

03 — Find → Research → Enrich → Outreach, which names the four stages those columns fall into and gives you a way to locate any failure to one of them.

Reference for this lesson: Tables, Actions, Credits, Import.