Headcount & Opex Plan
Rolls a hiring plan into fully-loaded monthly opex with a headcount overlay and a cost-growth narrative.
2026 Headcount & Opex plan
$27.9M
annualized opex · 124 roles by period end
- Loaded cost
- Headcount
Monthly loaded opex grew +27.9% across the plan to $2.33M.
| Period | Headcount | Loaded cost |
|---|---|---|
| Q1 2026 | 97 | $1.82M |
| Q2 2026 | 109 | $2.04M |
| Q3 2026 | 118 | $2.21M |
| Q4 2026 | 124 | $2.33M |
Finance · updated weekly
Demo data is illustrative. Replace with your own typed data prop.
How it computes
Headcount roll-forward from a hiring plan, costed as headcount × (annual salary / 12) × loaded rate.
hcₜ = startHc + Σ hires₀..ₜ; loadedCostₜ = Σ_dept hcₜ·(salary/12)·loadedRate; annualOpex = costₜ·12Assumptions
- Hires accrue full cost in the month they land (no mid-month proration).
- No attrition — everyone hired stays.
- Loaded rate defaults to 1.3 (30% on top of base), overridable per department.
Honest about
- One average salary per department — no junior/senior split or compa-ratio.
- Annualized opex is the terminal month × 12, assuming the final headcount is steady-state, not a weighted year total.
- An empty plan yields 0 opex and starting headcount rather than an error.
Use it with your data
Data contract
Passed via the data prop — an object: validated at runtime, so a bad shape degrades to the error state rather than crashing.
| Field | Type | Required |
|---|---|---|
| plans | array | yes |
| periods | array | yes |
Static props
import { FpaHeadcountOpex } from "@/components/blocks/fpa-headcount-opex/fpa-headcount-opex";
<FpaHeadcountOpex data={myData} />Client fetch (SWR)
const { data, isLoading, error } = useSWR("/api/metric", fetcher);
// route isLoading/error through <ChartStates>, then:
<FpaHeadcountOpex data={data} />Server component (RSC)
const data = await fetch(url, {
next: { revalidate: 3600 },
}).then((r) => r.json());
<FpaHeadcountOpex data={data} />Map arbitrary rows
import { mapRows } from "@/lib/sextant/column-map";
const out = mapRows(rows, { /* contractKey: "yourColumn" */ }, dataSchema);
if (out.ok) <FpaHeadcountOpex data={out.data} />;Make it yours
Every customization below is an optional prop — omit them all and you get the defaults shown above. Recolor, reformat, restyle, or drop the card chrome without forking the component.
Recolor or rename a series (opex, headcount)
<FpaHeadcountOpex
series={{ opex: { color: "var(--chart-3)", label: "…" } }}
/>Format numbers (currency / locale)
const eur = new Intl.NumberFormat("de-DE", {
style: "currency",
currency: "EUR",
notation: "compact",
});
<FpaHeadcountOpex valueFormatter={(n) => eur.format(n)} />Replace or hide the narrative
<FpaHeadcountOpex narrative="Your own one-liner." />
// …or hide it entirely:
<FpaHeadcountOpex narrative={false} />Restyle any region
<FpaHeadcountOpex
className="max-w-xl"
classNames={{ body: "bg-muted/20" }}
/>Drop the card chrome (headless plot)
import { FpaHeadcountOpexPlot } from "@/components/blocks/fpa-headcount-opex/fpa-headcount-opex";
// Just the chart body — bring your own card/layout:
<FpaHeadcountOpexPlot data={data} config={config} />