↓ Skip to main content
The Shape of It
The Shape of It · building your own tools

Build your own dashboard

A dashboard looks like a design problem. It is really four quiet engineering decisions, and your agent will make all four before you have finished describing what you want to see.

Ben Schmidt · a build walkthrough · ships a dashboard checklist

Built in parts · Part 1 is live · part of Build your own tools, more coming

Your numbers already exist. They are just scattered: a little in your payment tool, a little in a spreadsheet, a little in the app’s own database. A dashboard is the simple act of deciding to put the few that matter in one place you can glance at.

This is the most satisfying first thing to build, because the itch is so concrete. You are tired of logging into four tools to answer one question. So you say to your agent, “build me a dashboard of my key numbers,” and it cheerfully does, and it works on your laptop that afternoon. That is real, and you should feel good about it.

But “build me a dashboard” is not one instruction. Underneath it are four separate decisions about where the numbers come from, where they rest, how often they refresh, and what you actually show. Your agent will settle all four in the first minute, silently, usually by reaching for whatever is quickest to type. Most of the time that is fine for a tool only you use. The point of this page is to let you see the four decisions clearly enough to overrule the one or two that matter for what you are building.

Who this is for

Anyone who wants their own numbers in one view and is willing to direct an agent to build it, whether or not you write the code yourself.

What you'll leave with

The four decisions a dashboard is made of, a worked build from scratch, and a sense of what changes the day you share it.

How to read this. Everything below starts as a one-line verdict you can skim in a couple of minutes. Open only the parts you care about for the depth. Dotted terms like give you a plain definition on hover or tap.

First, what could it even look like?

#

Before any engineering, it helps to see what you are actually asking for. “A dashboard” is really one of a few shapes. Here are the common ones. The one in your head is probably on this page.

Most real dashboards are a mix: a couple of scoreboard numbers up top, one chart, a list underneath. Knowing which shapes you want is the first thing to hand your agent, because “a dashboard” means all three of these and it will guess which you meant.

Where does it live, and how do you get it?

#

This is the decision people cannot see coming, because in your head “just show it to me” feels like one thing. It is not. These options look equally simple and are wildly different amounts of work.

View it onyour laptopA file youopenA PDFOn a server(a URL)Emailed toyou weeklyEASY · you basically already canHARD · a real running system
Same five words to you ("just send it to me"), very different amounts of machine underneath.

Viewing it on your laptop, opening a saved page, or generating a are all easy, because nothing has to keep running: you ask, it makes the thing, you look at it. Putting it on a server so there is a is a step up, because now something has to stay up around the clock.

And “just email it to me every Monday” is quietly the hardest one on the row. It needs all of that plus three more moving parts: something that wakes up on a schedule, something that turns the live page into an image or PDF, and an email system that actually gets delivered instead of landing in spam. It sounds like the smallest ask. It is the biggest. Knowing that before you ask is exactly the kind of thing this page is for.

How the numbers get in

#

The numbers live in other tools. Getting them into your dashboard happens one of two ways, and the difference is bigger than it looks from the outside.

PULLyou ask, on a scheduleYourdashboardA source"anything new?"copied backPUSHit tells you, instantlyA sourceYourdashboard"new number!"the moment it changes
Two directions for the same data. Pull: your dashboard reaches out and asks, on a schedule. Push: the source announces the change the instant it happens.

Pull is you reaching out: your dashboard asks each source “anything new?” on a schedule and copies back the answer. It is simple, you control the timing, and the only cost is that the numbers are as fresh as your last check. Push is the reverse: the source notifies you the moment something changes, usually through a . It is as live as it gets, and it is more moving parts to set up and keep working. For a dashboard you glance at, pull wins almost every time.

Where you pull from is its own small ladder. The easiest source is a you drop in by hand. The most common is an , the doorway most tools open for code. And increasingly there is the , a doorway designed for agents, which can make the whole connection dramatically less work when a tool offers one.

▶
Get your agent to choose the mechanism on purposecopy for your agent
Make it name how it will reach each source, and justify pull over push unless live truly matters.

An agent will often default to calling sources live on every page load, which is neither pull-on-a-schedule nor push, and tends to be the fragile worst of both. Make the choice explicit.

Ask your agent
For each source
For each place this dashboard pulls from, tell me how you will reach it (a file export, an API, or an MCP server) and whether you are using a scheduled pull or a push. Default to a scheduled pull and justify any push by a real need for live data.
If a tool offers MCP
Does this source offer an MCP server? If so, would using it meaningfully simplify the connection versus calling its raw API, and what would change in how we pull the data?

How it's actually built

Those are the shapes. Underneath, a dashboard is a small pipeline: the numbers flow left to right through four stages, and each stage is one decision you get to make on purpose. Tap a stage to jump to it.

scattered raw numbersone live view

Pull the numbers in, keep them, refresh them, show them. Build left to right, and most of the work is deciding how little you need at each stage.

The shape of a dashboard

#

Hold this one picture and the rest follows: a dashboard pulls numbers from somewhere, keeps a copy, refreshes that copy on some rhythm, and draws the result on a screen. Source, store, refresh, display. Every dashboard ever built is some version of those four, and the whole craft is noticing how little you actually need of each. A tool just for you can skip corners that a tool for a hundred people cannot. Knowing which corner you are cutting, and on purpose, is the difference between a quick win and a thing that quietly lies to you.

The four decisions

#

Verdict first. Open one for what the decision really is, the lazy default your agent will reach for, and the question that forces a better choice.

▶
Source · where the numbers come fromstart here
The decision here is not the mechanism, it is the count: how many sources, and how painful is the worst one?

Your numbers live somewhere already: inside a payment tool like Stripe, inside your app’s own database, inside a spreadsheet you keep by hand. Each of those is a source. How you reach each one, and pull versus push, is covered just above in how the numbers get in. The decision here is the one people skip: how many sources does this really need, and how painful is the worst of them?

One source is a weekend. The honest difficulty of most dashboards is “I need three different places and they all speak differently,” and knowing that before you start is what keeps a quick win from turning into a slog.

Ask your agent
If you're scoping the build
List every source this dashboard genuinely needs, and for each one tell me how hard it is to reach and which single one will be the most work. Then tell me if any are not worth including for version one.
If one source is painful
This source has no clean API. What are my real options for getting its data, and which is least fragile?
▶
Store · where the numbers restthe quiet decision
For a personal dashboard, keep a small local copy rather than hitting every source live. A file or SQLite is almost always enough.

Here is the decision most people do not realize they are making. Do you fetch the numbers fresh from the source every single time, or do you pull them once, keep a copy, and read from the copy? Keeping a copy is a , and for a dashboard it is almost always the right move: your page loads instantly, you stop hammering the source, and the dashboard still works for a minute if a source hiccups.

That copy has to live somewhere, which is its own small decision with real trade-offs. For a personal dashboard it is genuinely tiny: a flat file or an on-device database is plenty. You only need more the day the dashboard is shared and busy. That whole decision has its own page.

Ask your agent
If you're choosing the copy's home
For a dashboard only I use, where should the cached numbers live? Argue for the simplest option that works, not the most capable one.
▶
Refresh · how the numbers stay currentwhere people over-build
You almost never need real-time. A scheduled pull every few minutes or hours into your local copy is simpler and good enough.

Now that you keep a copy, you have to decide how often to refresh it. The instinct is “live, always up to the second.” You rarely need that, and chasing it is where personal dashboards turn into a tangle. The simple pattern is : a small job wakes up on a schedule, pulls fresh numbers from each source into your local copy, and goes back to sleep. The dashboard just reads the copy. The schedule itself is usually a job.

The question that sets the whole design is not technical, it is about you: how stale is too stale? For most personal dashboards the true answer is “an hour old is completely fine,” and that answer lets you build the simplest possible version.

Decide how fresh you actually need the numbers to be. That one answer quietly determines how hard the whole thing is to build.

Ask your agent
If you're setting the rhythm
How fresh do these numbers actually need to be for me to make decisions off them? Then recommend the simplest refresh approach that meets that, and no fresher.
If you were told you need real-time
Do I genuinely need real-time updates here, or would a scheduled pull every few minutes be simpler and just as useful? Make the case both ways.
▶
Display · what you actually showrestraint wins
Show the two or three numbers that would change what you do this week. A wall of charts is the most common way a dashboard becomes useless.

This is the fun part and the easiest to get wrong. You already saw the three shapes at the top of the page: the scoreboard, the charts, the list. Most good dashboards are a small mix of them, and the mistake is always more. An agent will happily give you twelve charts, and twelve charts is noise you will stop looking at inside a week. A dashboard earns its keep when it answers one question at a glance: is anything different, and do I need to act? That usually means a few big numbers, maybe one trend line, and almost nothing else.

The discipline is to pick the handful of numbers that would actually change a decision, and cut the rest, however interesting they look. A number you will never act on is decoration.

Ask your agent
If you're deciding what to show
Here are the numbers I could show. Help me cut this to the two or three that would actually change what I do this week, and tell me what each one should look like.
If it already feels cluttered
This dashboard has too much on it. Which elements am I genuinely acting on, and which are just decoration I should remove?

Go deeper: the ideas underneath

#

Three concepts the decisions above lean on, in plain terms, each with a prompt that makes your agent apply it to your build.

▶
Fresh enough, not fresh alwaysconcept
A cached number is always a little out of date. The skill is deciding how out of date is acceptable.

The moment you keep a copy of a number, that copy starts aging. The source has moved on; your dashboard has not caught up yet. This is called staleness, and it is not a bug to eliminate, it is a dial to set. A dashboard refreshed every hour is up to an hour stale, and for almost everything personal that is completely fine. Trying to drive staleness to zero is exactly the over-engineering that turns a weekend build into a month.

The one place it bites: showing a stale number next to a timestamp that implies it is live. If you show “live revenue: $4,210” and it is actually an hour old, you have not saved time, you have built a small liar. Label the freshness honestly (“as of 2pm”) and the problem disappears.

Copy for your agent
Apply it to your build
For each number on my dashboard, how stale can it get before it misleads me, and does the page make its freshness honest and visible?
▶
Pull on a schedule, pull on demand, or be pushedreference
Three ways numbers get fresh. For a personal dashboard, a scheduled pull is almost always the right one.

There are really only three ways your copy gets updated. You pull on a schedule (a job refreshes it every so often, whether or not anyone is looking). You pull on demand (you refresh only when the page is actually opened, which saves work but makes the first load slow). Or you are pushed to (the source tells you the instant something changes, usually through a ). Push is the most “live” and the most fiddly to set up. For a dashboard you glance at, scheduled pulling wins on simplicity almost every time.

Copy for your agent
Apply it to your build
For my dashboard, compare a scheduled pull, an on-demand pull, and a webhook push for keeping the numbers fresh. Recommend one and say why it fits a tool I check a few times a day.
▶
A dashboard lies by defaultconcept
A single summary number hides as much as it shows. Know what each number is quietly averaging away.

Every number on a dashboard is a summary, and every summary throws information away on purpose. “Average response time: 1.2s” can look healthy while a tenth of your users sit at ten seconds, because the average buried them. “Revenue is up” can hide that one big customer carried the month and everyone else shrank. This is not dishonesty, it is what summarizing is, but a dashboard presents summaries with such confidence that it is easy to forget.

The habit worth building: for each headline number, ask what it is hiding. Often the fix is to show the shape, not just the summary (a distribution instead of an average, a breakdown instead of a total). You do not need all of that on a personal dashboard, but you should know which simplifications you accepted.

Copy for your agent
Apply it to your build
For each headline number on my dashboard, tell me what it is averaging or totaling away, and whether a hidden bad case could sit behind a healthy-looking figure.

Worked build: a dashboard for your own side project

#

The four decisions only click once you run them on something real. Here is the reasoning out loud for a dashboard you would actually want: the handful of numbers for a side project you run. Watch how each decision collapses toward the simplest option.

▶
Build it end to endwalkthrough
Two sources, a tiny SQLite copy, an hourly pull, three numbers on a page. It runs on your laptop or a five-dollar box.

Say you run a small paid app and you are tired of opening Stripe in one tab and your app’s admin in another just to see how the week is going. You want one page: signups this week, revenue this month, and how many people actually came back.

Source. Two places have what you need. Stripe has an for the revenue, and your app already has its own database with the signups and the activity. So, two sources, both reachable in code. Your agent’s first instinct will be to call both live on every page load. Note it, and overrule it in the next step.

Store. You do not want to hit Stripe every time you glance at the page, so you keep a small local . How small? Three numbers and a little history. This is the storage decision from the storage page, and here it collapses almost instantly: an on-device SQLite file is more than enough, no server, nothing to run. A flat file would even do, but SQLite costs nothing extra and makes the little bit of history easy to keep.

Refresh. How fresh do these numbers need to be? Honestly, an hour old is fine, you are not trading stocks, you are checking in. So a small job wakes up every hour, pulls from Stripe and your app database into the SQLite copy, and sleeps. The page just reads the copy, so it loads instantly and still works if Stripe is briefly down.

Display. The temptation is a grid of charts. Resist it. Three big numbers (signups this week, revenue this month, weekly active) and one small trend line underneath is the whole thing. Each of those three would actually change what you do this week; nothing else earns its place yet. Label them “as of 2pm” so you are never fooled into thinking they are live.

Add it up and the build is small on purpose: an hourly script, one SQLite file, one plain page, running on the laptop you already have or a cheap always-on box if you want to see it from your phone. No server to speak of, no real-time anything, and every corner you cut you cut knowingly.

The pick. Two sources pulled hourly into one SQLite file, three numbers and a trend on a single page. The whole design was set by one answer: an hour of staleness is fine. That let every other decision drop to its simplest form.
Ask your agent
Do this for your own dashboard
Walk the four dashboard decisions out loud for the one I am actually building: source (where each number comes from), store (where the copy lives), refresh (how fresh I truly need it), and display (the few numbers worth showing). Then propose the simplest build that fits, and name the one answer that decided the shape.

When your dashboard becomes a product

#

Everything above assumed one user: you. The day you show it to someone and they say “can I have my own login,” you have stepped from a personal tool onto a different rung, and a cluster of new decisions switches on at once. You do not need them for yourself. You need all of them the moment the data is other people’s.

Here is the honest version of that jump. Each of these is a page of its own eventually; for now, the point is to recognize that they appear together, and why.

▶
Who are you? (authentication)new on this rung
The moment more than one person logs in, the app has to prove who each visitor is. That is a real subsystem, not a checkbox.

A personal dashboard never asked who you were, because the answer was always “me, on my laptop.” Add a second person and the app suddenly needs : a trustworthy way to prove each visitor is who they claim. This is the single most common thing people underestimate and the most dangerous to improvise. The right move on this rung is almost always to let a dedicated service handle logins rather than rolling your own.

Ask your agent
If you're adding logins
I need to add real logins to this dashboard. Make the case for using an established authentication service rather than building my own, and tell me what I am responsible for either way.
▶
What are you allowed to see? (authorization)new on this rung
Logging in is only half of it. Now the app must make sure each person sees only their own numbers, not everyone's.

Knowing who someone is () is different from deciding what they may see (). The instant your dashboard holds more than one person’s data, every single query has to be scoped to the right person, or someone will eventually load the page and see numbers that are not theirs. This is the most common serious bug in shared apps, and an agent will not add the scoping unless you make it a rule.

Ask your agent
If multiple people share the app
This dashboard now holds several users' data. Show me how to guarantee each request can only ever read its own user's rows, and where that guarantee could leak.
▶
It is their data nownew on this rung
Other people's data turns the storage decision serious: real backups, a tested restore, and care about what you even collect.

When the only data at risk was yours, a dropped database was a bad afternoon. When it is customers’ data, the same loss is an incident you have to answer for, and a leak of it can be a legal one. This is exactly the far end of the storage page: recovery stops being optional (a copy you have never restored is not a backup), and what you choose to collect in the first place starts to matter, because the safest data to lose is the data you never stored.

Ask your agent
If it now holds other people's data
This dashboard now stores data belonging to other people. Walk me through what I newly owe them: backups with a tested restore, what personal data I am holding, and what I could avoid collecting entirely.
▶
It has to be upnew on this rung
A tool for you can be down while you sleep. A tool others depend on cannot, and that single expectation reshapes where and how it runs.

Your personal dashboard could crash overnight and you would fix it with coffee. Once other people open it during their workday, “it is down” becomes their problem and your reputation. You do not need heroic uptime on day one, but you do need to decide, on purpose, where it runs so it stays up without you watching, and how you find out when it does not. That is the beginning of the operations half of software, and it is a real rung, not a footnote.

Ask your agent
If people now depend on it
People now rely on this dashboard during their workday. What is the simplest setup that keeps it reliably up without me babysitting it, and how would I even know if it went down?

None of this means you should build the product version first. It means the opposite: build the personal one, enjoy it, and recognize the exact moment, the first shared login, when these decisions switch from “skip it” to “all of them, now.” That recognition is the whole skill. The rest is asking the right question at each one.

The tool

Hand this to your agent before it builds your dashboard

Before you build this dashboard, decide out loud, for THIS project:
  1. Source  - every place a number comes from, and how we reach each (API, DB, file, manual).
  2. Store   - hit sources live, or keep a local copy? Where does the copy live? Prefer simplest.
  3. Refresh - how stale is acceptable? Simplest refresh that meets it (scheduled pull beats real-time).
  4. Display - the 2-3 numbers that change a decision this week; cut the rest; label freshness honestly.
Then build the SMALLEST version that satisfies all four, and name every corner you cut.
If this will ever have more than one user, flag it: logins, per-user data scoping, real backups,
and uptime all become required at once.
The Shape of It · a teaching piece by Ben Schmidt