The open-source bake-day planning engine for sourdough & micro bakeries.
Turn a day's orders into the three things you actually need at 4 a.m.: a time-reversed bake schedule, scaled baker's-percentage formulas, and one aggregated shopping list. Zero dependencies, pure functions, MIT licensed.
This is the production-math core behind DoughPlan β the back-of-house planning app for home & micro bakeries (20β150 loaves/week). The engine is open source so you can read it, trust it, and build on it. If you'd rather not write JSON, the full visual planner (labels, packing lists, multi-bake-day, printable production sheets & shareable plan links) lives at doughplan.com.
π Docs & live API reference: saschaheyer.github.io/doughplan
You don't plan a bake day forward from when you wake up β you plan it
backward from when the bread has to be out of the oven for market. Three
breads, two ovens, twenty-six loaves, one fridge: the math of when to feed the
levain and how much flour to buy is fiddly and easy to get wrong on paper.
doughplan does it deterministically.
- Baker's percentages done right β flour is always 100%; every formula scales linearly and conserves mass exactly.
- Time-reversed scheduling β every step is an offset before out-of-oven, so the same formula produces a real wall-clock plan for any target time.
- Cross-product aggregation β bake three products on one day and get a single merged schedule and one combined shopping list.
# Install straight from GitHub (zero dependencies, Node 18+):
npm install github:SaschaHeyer/doughplan
# β¦or clone and run the CLI directly:
git clone https://github.com/SaschaHeyer/doughplan
cd doughplan && node bin/cli.js --helpRequires Node 18+. No dependencies.
doughplan plan examples/bakery.json --date 2026-06-20 --time 08:00π₯ DoughPlan β bake day 2026-06-20
32 units Β· 28.00 kg dough Β· 13.98 kg flour Β· out of oven 08:00
β± SCHEDULE (planned backward from out-of-oven)
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Fri 03:00 PM Feed levain Country Sourdough Γ24, Seeded Spelt Γ8
Fri 09:00 PM Autolyse Country Sourdough Γ24, Seeded Spelt Γ8
Fri 10:00 PM Add levain + salt ...
Sat 04:00 AM Into the fridge ...
Sat 07:00 AM Preheat Dutch oven ...
π₯ Sat 08:00 AM Out of the oven Country Sourdough Γ24, Seeded Spelt Γ8
βοΈ FORMULAS
Country Sourdough Γ24 (75% hydration Β· Wheat)
Bread flour 90% 9.87 kg
Water 75% 8.22 kg
...
π SHOPPING LIST (aggregated across all products)
Bread flour 10.77 kg
Water 10.58 kg
...
Pipe it from anywhere:
cat bakery.json | doughplan plan --date 2026-06-20import { buildPlan, scaleProduct, hydration } from "doughplan";
const products = [{
name: "Country Sourdough",
unitWeightG: 900, // raw dough weight per loaf
ingredients: [
{ name: "Bread flour", pct: 100, isFlour: true, allergen: "Wheat" },
{ name: "Water", pct: 75 },
{ name: "Starter", pct: 20, allergen: "Wheat" },
{ name: "Sea salt", pct: 2 },
],
schedule: [ // offsetMin = minutes BEFORE out-of-oven
{ label: "Feed levain", offsetMin: 600 },
{ label: "Mix", offsetMin: 540 },
{ label: "Shape", offsetMin: 240 },
{ label: "Bake", offsetMin: 45, bake: true },
{ label: "Out of oven", offsetMin: 0, bake: true },
],
}];
const orders = [
{ date: "2026-06-20", items: [{ product: "Country Sourdough", qty: 24 }] },
];
const plan = buildPlan({ products, orders, date: "2026-06-20", bakeTime: "08:00" });
plan.totals; // { units: 24, doughG: 21600, flourG: 10964.5 }
plan.schedule; // [{ at: Date, label, bake, items: [{product, units}] }, ...]
plan.formulas; // [{ product, units, hydration, allergens, ingredients: [{name, pct, grams}] }]
plan.shopping; // [{ name, grams, isFlour }, ...] aggregated across products| Function | Returns |
|---|---|
buildPlan({ products, orders, date, bakeTime }) |
full plan: schedule, formulas, shopping, totals |
scaleProduct(product, units) |
ingredient grams for N units (mass-conserving) |
buildSchedule(productLines, outOfOven) |
merged, time-ordered schedule |
hydration(ingredients) |
water as a % of flour |
totalPct(ingredients) / flourPct(ingredients) |
percentage sums |
allergensOf(product) |
de-duplicated allergen list |
Data shapes are documented as JSDoc in src/index.js.
For a product at unitWeightG Γ units, total dough weight is known. Because
the baker's percentages sum to totalPct (e.g. 197% for a 75%-hydration loaf),
flour weight is doughTotal Γ 100 / totalPct, and each ingredient is
flourWeight Γ pct / 100. Mass is conserved to the gram. The schedule anchors
every step to outOfOven β offsetMin, then merges steps from different products
that fall in the same 5-minute window. See src/bakers-percentage.js
and src/schedule.js.
npm test # node --test, zero deps- Levain build sub-schedule (feed ratios β ready time by temperature)
- Cottage-food label generator (allergens, net weight, producer info)
- CSV/ICS export of the schedule
- Per-order packing lists
PRs welcome. If you run a bakery and the model doesn't fit how you work, open an issue β that feedback shapes the hosted product too.
doughplan is the engine. DoughPlan is the full
product built on top of it β a visual planner with order entry, printable
cottage-food labels, packing lists, multi-bake-day planning, printable production sheets, and shareable plan links,
priced for micro bakeries (not the $200β350/mo enterprise tools). Free tools
you can use right now, no signup:
- Baker's percentage calculator
- Sourdough starter / levain calculator
- Dough temperature (DDT) calculator
MIT Β© DoughPlan