---
title: "Cups to grams needs a density table — Tiny Plates"
description: "Cups to grams depends on the ingredient. A grams-per-cup table for flour, sugar, butter and more, plus a small TypeScript converter for recipe apps."
url: "https://www.tinyplates.dev/blog/cups-to-grams"
---

# Cups to grams needs a density table

A cup of flour and a cup of sugar don't weigh the same. Here's a table and a converter.

21 October 2026

A cup of flour weighs about 120 grams. A cup of sugar weighs about 198\. Same cup, same kitchen, almost 80 grams apart.

That's the whole problem with converting cups to grams. A cup measures space, not stuff. How much a cup weighs depends on what you put in it. So if your recipe app turns every cup into one fixed number of grams, somebody's cake is going to come out wrong.

You need a number per ingredient. That number is density: how many grams fit in a millilitre, or in a cup. And once you start collecting them, you find out it's even fussier than that.

Take brown sugar. Packed into the cup, it's 213 grams. Spooned in loosely, it's a lot less. Flour that's sifted weighs less than flour scooped straight from the bag, because sifting adds air. Even the product matters. King Arthur's chart lists its own rolled oats at 113 grams a cup, and old-fashioned or quick oats at 89.

Salt is the best example. One tablespoon of table salt is 18 grams. Morton's kosher salt is 16\. Diamond Crystal kosher salt is 8\. Three things called salt, and one weighs less than half of another, by the spoon.

So a good converter knows two things about each ingredient. What it is, and how it went into the cup.

## Which cup, though?

Before the table, one more wrinkle. There isn't just one cup.

A US customary cup is about 236.6 ml. US nutrition labels round that to 240 ml. Australia and New Zealand use a metric cup of 250 ml. Those are only a few percent apart, which won't ruin dinner. But if you're writing code, pick one and write down which.

Swedish recipes skip cups altogether and use decilitres. 1 dl is 100 ml, so a US cup is about 2.4 dl. That doesn't get you out of density, though. "2 dl vetemjöl" is still a volume of flour. A Swedish app that wants grams has the exact same problem. We wrote about how Tiny Plates handles Swedish units in our [post on Swedish recipes](https://www.tinyplates.dev/blog/recept-api) (it's in Swedish).

Here's a table you can copy. Every number comes from [King Arthur Baking's ingredient weight chart](https://www.kingarthurbaking.com/learn/ingredient-weight-chart), which bakers have trusted for years. King Arthur lists some ingredients by the half cup, quarter cup or tablespoon. For those, I multiplied up to a full cup, so the last column can be off by a gram or two.

| Ingredient                              | King Arthur lists | Grams per cup |
| --------------------------------------- | ----------------- | ------------- |
| All-purpose flour                       | 1 cup = 120 g     | 120           |
| Bread flour                             | 1 cup = 120 g     | 120           |
| Unbleached cake flour                   | 1 cup = 120 g     | 120           |
| Whole wheat flour (King Arthur Premium) | 1 cup = 113 g     | 113           |
| Granulated sugar                        | 1 cup = 198 g     | 198           |
| Superfine (caster) sugar                | 1 cup = 190 g     | 190           |
| Brown sugar, packed                     | 1 cup = 213 g     | 213           |
| Confectioners' sugar, unsifted          | 1 cup = 113 g     | 113           |
| Cocoa, unsweetened                      | ½ cup = 42 g      | 84            |
| Cornstarch                              | ¼ cup = 28 g      | 112           |
| Rolled oats (old-fashioned or quick)    | 1 cup = 89 g      | 89            |
| Long grain rice, dry                    | ½ cup = 99 g      | 198           |
| Butter                                  | ½ cup = 113 g     | 226           |
| Peanut butter                           | ½ cup = 135 g     | 270           |
| Honey                                   | 1 tbsp = 21 g     | 336           |
| Vegetable oil                           | 1 cup = 198 g     | 198           |
| Olive oil                               | ¼ cup = 50 g      | 200           |
| Milk                                    | 1 cup = 227 g     | 227           |
| Buttermilk                              | 1 cup = 227 g     | 227           |
| Water                                   | 1 cup = 227 g     | 227           |

Look at the water. A US cup of water really weighs about 237 grams. King Arthur says 227, which is 8 ounces. That's not a mistake, it's a kitchen number. These charts are made for people with scales, and round numbers are easier to bake with. Keep that in mind if you mix this table with one from somewhere else. Different sources fill the cup differently and round differently, so their numbers won't match exactly.

## A small converter in TypeScript

Here's a converter you can drop into a project. It turns a volume into grams when it knows the ingredient, and says so when it doesn't.

```ts
// Millilitres in each unit. The cup is the US customary cup,
// which is the cup King Arthur's chart is written for.
const ML_PER_UNIT = {
  cup: 236.588,
  tbsp: 14.787,
  tsp: 4.929,
  ml: 1,
  dl: 100,
  l: 1000
} as const

type VolumeUnit = keyof typeof ML_PER_UNIT

// Grams per US cup, from King Arthur Baking's ingredient weight chart.
// A Map, so a name like "constructor" can't match something on Object.prototype.
const GRAMS_PER_CUP = new Map<string, number>([
  ['all-purpose flour', 120],
  ['bread flour', 120],
  ['whole wheat flour', 113],
  ['granulated sugar', 198],
  ['brown sugar, packed', 213],
  ["confectioners' sugar", 113],
  ['cocoa', 84],
  ['rolled oats', 89],
  ['butter', 226],
  ['honey', 336]
])

export function toGrams(
  amount: number,
  unit: VolumeUnit,
  ingredient: string
): number | undefined {
  const gramsPerCup = GRAMS_PER_CUP.get(ingredient.trim().toLowerCase())

  // Unknown ingredient: don't guess. Let the caller keep the volume.
  if (gramsPerCup === undefined) {
    return undefined
  }

  const cups = (amount * ML_PER_UNIT[unit]) / ML_PER_UNIT.cup

  // Round once, at the end.
  return Math.round(cups * gramsPerCup)
}

toGrams(1.75, 'cup', 'all-purpose flour') // 210
toGrams(3, 'dl', 'granulated sugar') // 251
toGrams(1, 'cup', 'mashed banana') // undefined

```

A few choices in there are worth copying. Everything goes through millilitres, so dl and tablespoons work for free. The math runs in full precision and rounds once at the very end. Rounding halfway through adds up to real errors on a big recipe. And an unknown ingredient returns `undefined` instead of a guess. Showing "1 cup mashed banana" is fine. Showing "240 g mashed banana" because you assumed it weighs like water is not.

The hard part isn't this function. It's knowing that "1¾ cups all-purpose flour, spooned and leveled" is all-purpose flour, 1.75 and cups. That's ingredient parsing, and we went through it in [how to parse ingredient lines](https://www.tinyplates.dev/blog/parse-ingredient-lines).

## How Tiny Plates does it

The Tiny Plates API does this for you on a single recipe. Add `units=metric`:

```bash
curl 'https://api.tinyplates.dev/recipes/69e22c71d0295ac8a9011ecd?units=metric' \
  -H 'Authorization: Bearer rd_your_api_key'

```

That's a banana bread. The source asks for "1¾ cups all-purpose flour" and "¾ cup sugar". Here's what comes back, trimmed:

```json
{
  "conversion": {
    "system": "metric",
    "unweighed": ["unsalted butter", "banana"]
  },
  "recipe": {
    "ingredients": [
      {
        "display": "225 g all-purpose flour, spooned into measuring cup and leveled-off",
        "ingredientId": "all-purpose-flour",
        "quantity": { "value": 225, "unit": "g" }
      },
      {
        "display": "155 g sugar",
        "ingredientId": "sugar",
        "quantity": { "value": 155, "unit": "g" }
      },
      {
        "display": "½ cup unsalted butter, softened (1 stick)",
        "ingredientId": "unsalted-butter",
        "quantity": { "value": 0.5, "unit": "cup" }
      }
    ]
  }
}

```

Under the hood it's the same idea as the converter above, with a few extra rules.

The density table is in grams per millilitre, and it's keyed by the ingredient's canonical id, like `all-purpose-flour`. If a recipe hasn't been matched to an id yet, it falls back to the ingredient's name. It's short on purpose. Only ingredients with a well-known density are in it, because a wrong density is worse than a volume you can measure yourself. It also matches whole names only, never a word inside a name. Cream pours, but cream cheese doesn't.

That's why the butter above stays in cups. The table knows `butter`, but not `unsalted-butter` yet. So the line keeps its cup, and the name shows up in `conversion.unweighed`. Your app can use that to explain why one line still says "cup". Same for the mashed banana.

Not every volume gets weighed. Cups, fluid ounces, pints, quarts and gallons do. Teaspoons and tablespoons stay as they are, because nobody weighs a teaspoon of vanilla. Millilitres and decilitres stay too, since a metric recipe is already written that way. And liquids are poured, not weighed. Even though we know what water weighs, a metric recipe asks for 240 ml of water, not 240 g.

The API counts a cup as 240 ml, the nutrition label cup. With that cup, our flour density works out to about 127 grams. That's a bit above King Arthur's 120, which is why the banana bread gets 225 g and not 210\. It's the kind of spread you'll see between any two tables. For baking where it really matters, the recipe's own weights always win.

The math runs in full precision and gets rounded once, at the end, the way a cook would write it. Grams land on a step a kitchen scale can read. Oven temperatures convert too, rounded to the nearest five degrees. And the source line is never touched. It stays in `original`, so you can always show what the recipe really said.

The same conversion works going the other way. `units=imperial` turns grams into ounces and millilitres into cups and spoons. It also works together with `servings`, so you can ask for a recipe for six, in grams, in one call. Every field is in the [get a recipe reference](https://www.tinyplates.dev/docs/api/get-recipe), and the [shopping list post](https://www.tinyplates.dev/blog/one-shopping-list-for-a-week-of-recipes) shows how the same units add up across a week of recipes.

If you just need a table, take the one above. It's King Arthur's, and they've earned the trust. If you'd rather not keep one yourself, [grab a free key](https://www.tinyplates.dev/sign-up) and let the API do the weighing.
