Start
Getting started
A model of a web shop on a page, in four steps. You need a React 19 app; a fresh one is
npm create vite@latest shop -- --template react-ts.
1. Install
npm i @loadmap/react react react-dom
@loadmap/react brings the model, the view and the components. The layout runs in a Web Worker that the first diagram
starts; Vite and other bundlers that understand new Worker(new URL(…, import.meta.url)) pick it up with no setup.
No bundler, a CDN or one HTML file: Without a bundler.
2. Write the model and the view
The model is plain TypeScript: the load (a multiple of today), the parameters a reader can change, the flows and their rates, and the components that can run out, each with its demand and its capacity. The view says which boxes to draw and where the dots start.
import {
defineModel,
defineView,
edge,
estimated,
Loadmap,
measured,
node,
p,
pool,
store,
workers,
} from '@loadmap/react'
// the model: plain TypeScript, no React
const shop = defineModel({
title: 'Web shop',
load: p.load({ label: 'Visitors, × today', max: 50, default: 1 }),
params: { pods: p.select({ label: 'App pods', options: [2, 4, 8], default: 2 }) },
flows: { requests: { label: 'requests', rate: ({ load }) => 300 * load, unit: 'request' } },
components: {
app: {
name: 'App pods',
short: 'the app pods',
plural: true,
demand: ({ flows }) => flows.requests * 0.003,
capacity: ({ pods }) => measured(pods * 2, 'cores', 'pod CPU limit'),
over: 'requests wait and time out',
},
db: {
name: 'Postgres',
short: 'the database',
demand: ({ flows }) => flows.requests * 2,
capacity: estimated(5_000, 'queries/s', { source: 'last year’s load test', within: 0.3 }),
over: 'queries queue on the primary',
},
},
stages: { app: workers('app', { pods: ({ pods }) => pods, perPod: 4 }), db: store('db') },
routes: { requests: ['app', 'db'] },
})
// the view: which boxes to draw and where the dots start
const view = defineView(shop, {
nodes: {
users: node({ label: 'Browsers' }),
app: pool({ label: 'App', sub: ({ pods }) => `${pods} pods`, stage: 'app' }),
db: node({ label: 'Postgres', stage: 'db', shape: 'cylinder' }),
},
edges: [edge('users', 'app'), edge('app', 'db')],
flows: { requests: { from: 'users', color: 'accent' } },
})
export function App() {
return <Loadmap model={shop} view={view} theme="inherit" />
}
3. See it
Move Visitors past 2×: the app pods turn amber, and the verdict says they are the first limit, at 2.2×. Switch to 8 pods and the database takes over, somewhere between 2.9× and 5.4×: a range, because its capacity is an estimate within ± 30 %.
4. Make it yours
- Replace the numbers with yours, and say where each came from:
measured(…)for what you measured,estimated(…, { within: 0.3 })for what you did not.fitLinearfits a cost per request from a series of measurements. - Add
scenarios: { Today: {}, Proposed: { pods: 8 } }to compare designs, andgrowthto turn multiples into dates. - Add
expect: [{ target: 3 }]and a test that callsassertHolds(shop): a change that loses the headroom fails it. - Add a
storyto walk a reader through it a step at a time.
Concepts explains each of these. The same model can also be written as a .loadmap text and edited
next to its diagram: see the language and the editor.