catering-portions
v1.1.0
Published
Catering quantity data for 33 dishes, with both cooked serving weight and purchase yield, so you order the right amount instead of half of it.
Maintainers
Readme
catering-portions
Catering quantity data for 23 common dishes, with the one distinction most portion charts leave out: how much you serve is not how much you buy.
npm install catering-portionsWhy this exists
Search "how many pounds of brisket for 50 people" and you get a single number. That number is almost always the cooked serving weight, and the person asking is usually standing over a supplier order form. A whole packer brisket loses roughly half its weight to trimming and rendering, so ordering the cooked weight leaves you short by nearly half.
Every dish here carries both figures:
| Field | Meaning |
| --- | --- |
| servingOz | Cooked weight actually served per guest |
| yield | Purchase weight divided by cooked weight |
yield > 1means buy more than you serve. Meat, from trim and cook loss.yield < 1means buy less than you serve. Dry pasta and rice absorb water.yield = 1means what you buy is what you serve. Deli meat, ready-made salads.
Usage
import { DISHES_BY_SLUG, rowFor, rowsFor, traysFor } from "catering-portions";
const brisket = DISHES_BY_SLUG["brisket"];
rowFor(brisket, 50);
// { guests: 50, served: "16.6 lb", purchase: "33.1 lb", trays: "3 full trays" }Serving 50 people brisket means putting out 16.6 lb of cooked meat, which means buying about 33.1 lb raw. That gap is the entire point of the package.
rowsFor(brisket); // a row for every guest count the dish tabulates
traysFor(50, 18); // "3 full trays", from servings and per-tray yieldTwo halves are promoted into one full tray, because no caterer writes "2 half trays" on an order sheet.
API
| Export | Description |
| --- | --- |
| DISHES | DishSpec[], the full dataset |
| DISHES_BY_SLUG | Record<string, DishSpec> lookup |
| rowFor(dish, guests) | Served weight, purchase weight, and tray count for one guest count |
| rowsFor(dish) | rowFor across the dish's tabulated guest counts |
| traysFor(servings, perTray) | Readable half and full tray count |
| hasYieldGap(dish) | True when buying differs from serving |
| titleName(dish) / lowerName(dish) | Display forms that keep acronyms intact (BBQ stays BBQ) |
Each DishSpec also carries yieldNote (why the yield is what it is), purchaseAs (what you
actually order, such as "raw packer brisket"), answer (a one-line plain-language answer), and
notes (operational caveats, like brisket dropping to a quarter pound per person when served
alongside a second meat).
Fully typed. Zero dependencies. ESM.
Honest limits
These are standard food-service planning figures, not laboratory constants. Real yield moves with cut, trim level, cooking method, and holding time. Treat them as a starting point and calibrate against your own results. If you have measured figures that differ, please open an issue with what you observed, since that is exactly the kind of correction this dataset should absorb.
The dataset covers US-style catering portions and imperial units.
Contributing
Corrections to the numbers are more valuable than new features. Open an issue with your observed yield and the conditions behind it.
License
MIT. Extracted from the portion engine behind ZiaPilot, which quotes catering orders from a restaurant's own menu and tray sizes. The interactive version of this data lives at ziapilot.com/catering-portions.
