Beer Water Profiler

This page will determine how much of each ingredient you need to add to your base water to get as close to your target water as possible. Enter your base water, if different than distilled, enter your target water, choose how many gallons, and hit 'Compute optimal'. You can also manually enter the additives, and the resulting water will be changed accordingly. See below for explanations of the CSV buttons.

Please let me know what you think by sending me feedback! (Aaron Bloomfield,

Base water:
Target water:





Base water:
Target water:
Resulting water:
Difference (in ppm):


Measurement increment:

Total difference:












How it works

This web page uses a greedy algorithm to determine the optimal amount of each additive to add to the water. Thus, it is not guaranteed to be the best possible combination (greedy algorithms will achieve a good solution, but in this case, it is guaranteed to be the optimal solution). The 'total difference' is the sum of the difference row -- it's the total amount (in parts per million or ppm) that all the minerals are off from the target water. Note that it adds up the absolute values of the differences (thus, a negative difference -- indicating that the resulting water has a greater mineral content than the target water -- does not lower the total difference). The algorithm will try to add or subtract (when the amount is not already zero) some of each mineral. The amount it tries to add or subtract is the measurement increment that the user chooses. This yields 12 possible choices -- adding one of each mineral, and subtracting one of each mineral. Whichever has the lowest total difference is chosen as the next step, as long as the new total difference is less than the current total difference. The algorithm repeats until it cannot lower the total difference by adding or subtracting any more of the additives. (For those algorithmically inclined, I am aware that a lattice algorithm would guarantee the lowest total difference).



You can add a number of paramters to this page's URL to set the initial values of the above fields.

  • base: chooses the base water (use the 'short' name, such as 'london', which is the name in parenthesis in the drop-down list)
  • target: chooses the target water (again, use the short name)
  • calbase, magbase, sodbase, sulbase, chlbase, carbase: set the exact mineral amounts for the base water
  • caltarget, magtarget, sodtarget, sultarget, chltarget, cartarget: set the exact mineral amounts for the target water
  • gallons: set the gallons

For example, if you brew in Charlottesville, Virginia (my hometown), and want a 12 gallon batch, you can use this url: If you want to set the brew parameters to an alternative set for the water in Dortmund, Germany, you can use this url: (this sets the minerals of the desired target water to 249, 21, 65, 236, 100, and 256, respectively, as well as setting the gallons to 10). There is also a 'debug=1' parameter, which will print out a verbose log as it works. However, this is VERY slow, and will often cause your script to hang.


Water sources

The data used for the base and target water is from a number of sources, which are mostly listed below. See the Javascript code for exact details as to where each city's data is from.


CSV Output

The 'Display CSV data' button will display, between the two horizontal lines above, CSV output of the current values of the additives table. This can be done repeatedly to generate a multi-line CSV file (the header row is only inserted the first time). This is useful if you want to have a print out of, say, all the additives for a 12 gallon batch for various different target waters. The 'Clear CSV data' erases the CSV data listed there. The ' Generate full CSV' will generate, for the current base water and number of gallons, the optimal water for each of the possible target waters (except for distilled water and the current base water). Note that this last functionality will most like run into the maximum allowed browser script execution time (a window will pop-up asking if you want to continue running the script).



  • Nov 6, 2013: Something was not working right, but it seems to be fixed (I blame a browser upgrade).
  • May 15, 2011: Made the Javascript Firefox 4.0 compliant, and converted it to my new home page theme. And changed the URL.
  • August 12, 2008: Added the three CSV buttons and functionality. Also successfully validated the HTML. And made sure most of the data sets (all but 3) are free to use.
  • July, 2008: Initial version working properly.



This code (both Javascript and this HTML web page) is Copyright (c) 2008-2013 by Aaron Bloomfield (aaron (at) virginia (dot) edu)

It is released under the GNU General Public License. You may copy it and use it all you want, but please keep this attribution intact. For more details about the licensing, see