← All Writing

Distilled water + mineral drops, mid-recipe
↓ drop image here

Coffee + Code May 14, 2026 6 min read

Water chemistry for coffee: a developer's approach

Every water chemistry write-up starts the same way: distilled water is a blank canvas, and minerals are what actually extract flavor. I'd read Jonathan Gagne's book years ago as a barista, but it wasn't until I started coding Water Crafter that the method actually clicked for me.

Why water chemistry matters

Magnesium and calcium ions bond with coffee's flavor compounds during extraction — too little and the cup tastes flat and sour, too much and it turns muddy or chalky. Bicarbonate buffers acidity, which is why high-bicarbonate tap water often produces dull, flat coffee no matter how good the beans are.

Gagne's approach sidesteps unpredictable tap water entirely: start from distilled water — a truly blank slate — and add precise amounts of food-grade Epsom salt (magnesium sulfate) and baking soda (sodium bicarbonate) to hit a target profile.

Modeling Gagne's method in code

The math itself is simple stoichiometry, but it's the kind of simple that's easy to get subtly wrong. Here's a stripped-down version of the core calculation Water Crafter runs on every recipe change:

ts
interface MineralTarget {
  magnesiumPpm:   number; // Mg2+ target, mg/L
  bicarbonatePpm: number; // HCO3- target, mg/L
}

// Molar mass constants (g/mol)
const EPSOM_SALT_MG_FRACTION = 0.0986;    // MgSO4 7H2O
const BAKING_SODA_HCO3_FRACTION = 0.7238; // NaHCO3

function doseGramsPerLiter(target: MineralTarget) {
  const epsomSaltG  = target.magnesiumPpm   / (EPSOM_SALT_MG_FRACTION * 1000);
  const bakingSodaG = target.bicarbonatePpm / (BAKING_SODA_HCO3_FRACTION * 1000);

  return {
    epsomSaltGPerLiter:  round(epsomSaltG, 3),
    bakingSodaGPerLiter: round(bakingSodaG, 3),
  };
}

function round(n: number, places: number) {
  const f = 10 ** places;
  return Math.round(n * f) / f;
}

Scale that per-liter dose by batch size and you've got exact gram measurements for a 300ml pour-over or a 20-liter batch for a cafe — the ratio never changes, only the multiplier.

“The best coffee tools don't try to replace judgment — they just remove the arithmetic between you and the decision.”

What I'd do differently

If I started over, I'd model concentrate solutions from day one instead of bolting them on later — most people don't want to weigh 0.031g of baking soda on a kitchen scale, they want to make a stock solution and dose it in milliliters. That's next on Water Crafter's list.

For now, the tool is live in beta with the three presets above. If you brew with it, I'd genuinely like to hear how the cup tastes.

Related reading

Reflection

Why I started building coffee tools

The story of how a barista became a developer.

Coming Soon

AI

Exploring AI for specialty coffee

Where language models meet flavor notes.

Coming Soon