Skip to content

Ingredients

Ingredients are the core building blocks of any Gram recipe.

To declare an @ingredient, use the @ symbol. If the @ingredient name contains spaces or requires a specific quantity, you must append the quantity inside {} braces. If it is a single word without a specific quantity, the braces are optional (the quantity defaults to 1).

[Add] @salt and @ground black pepper{} to taste.

[Poke] Holes in @potatoes{2}.

To specify a unit of measurement (weight, volume, etc.), add it directly after the numeric value inside the braces, separated by an optional space.

[Place] @bacon strips{1kg} on a baking sheet and glaze with @syrup{1/2 tbsp}.

By default, the Gram Compiler scales an @ingredient linearly based on the number of portions requested. If you scale a recipe from 2 to 4 servings, an @ingredient with {100g} becomes {200g}.

Some @ingredient items (like salt, yeast, or spices) should not scale linearly. You can lock their quantity using the = modifier.

Season with @=salt{1 tsp} to taste.

This keeps the salt at 1 tsp regardless of how many servings the user calculates.

Gram provides several modifiers to alter how an @ingredient behaves in the parser and the shopping list. Modifiers are placed immediately after the @ symbol.

ModifierNameEffect
&ReferenceReferences an @ingredient previously declared. Does NOT add it to the shopping list again.
=FixedMarks the quantity as fixed (it will not scale with portions).
?OptionalMarks the @ingredient as optional.
-HiddenHides the @ingredient from the generated shopping list.
*Baker’s %Marks the @ingredient as the reference (100%) to calculate baker’s percentages.

Use ? to mark an @ingredient as optional — useful for garnishes or substitutions the cook may skip. Use - to hide an @ingredient from the generated shopping list entirely, e.g. something you always have on hand.

[Garnish] Sprinkle with @?thyme{} and a pinch of @-salt{} to taste.

The reference modifier is crucial for multi-step recipes. As a best practice, any time you mention an @ingredient after its initial declaration, you should use the & modifier.

The compiler’s behavior changes depending on whether you provide a new quantity with your reference:

  1. Pure Reference (No Quantity) When instructing the user to use an already declared @ingredient, use @& so it isn’t counted twice in the shopping list.
[Add] @flour{200g} to the bowl.

[Dust] The work surface with the @&flour.
  1. Additive Reference (With Quantity) Sometimes you need to use the same @ingredient multiple times with different additions throughout the recipe. Using @&ingredient{qty} tells the compiler: “This is the same @ingredient, please add this extra quantity to the total shopping list.”
[Add] @butter{100g} to the dough.

[Grease] Use @&butter{50g} to grease the pan. // The shopping list will correctly aggregate 150g of butter.

In baking, recipes are often built around the Baker’s Percentage, where the main @ingredient (usually flour) represents 100%, and all other items are expressed as a percentage of that weight.

Gram provides a dedicated modifier to mark the reference @ingredient. By placing a * after the @ symbol, you tell the Gram Compiler: “This is the 100% reference point”.

[Add] The @*flour{500g}, @water{350g} and @salt{10g}.

This allows tools (like the CLI or web renderers) to automatically calculate and display the baker’s percentages for all other items (e.g., Water: 70%, Salt: 2%) without you having to define them manually as relative quantities.

Often, an @ingredient requires preparation before use. You can define this directly within the declaration using parentheses ().

[Mix] @butter{1 stick}(room temperature) and @garlic{2 cloves}(peeled and minced).

You can rename an @ingredient for display purposes using a colon : immediately after the real name. This is useful for keeping the shopping list clean while using a colloquial name in the instructions.

Format: @Real Name:Display Name{Quantity}

Deglaze with @dry white wine:wine{100ml}.

The shopping list will aggregate this under “dry white wine”, but the rendered recipe will just say “wine”.

You can define acceptable alternatives for an @ingredient using the pipe | operator.

Add @milk{100ml}|@water{95ml}.

This works with short-hand preparations as well:

@onion{1}(peeled and chopped)|@shallots{2}(minced)

Recipes aren’t always exact. You can specify a range using a hyphen -.

Add @eggs{2-4}.

Pour @water{1.5-2l}.

Quantities accept fractions in three forms — a plain fraction, a mixed number, or a Unicode fraction glyph — all normalized to the same decimal value.

Add @sugar{1/2 cup}.

Add @flour{1 1/2 cups}.

Add @butter{1½ sticks}.

The compiler checks for semantic errors in your @ingredient declarations and will output specific warnings:

  • Invalid Modifier: If you combine incompatible modifiers (like ?*), the compiler warns INVALID_MODIFIER_COMBINATION and ignores them.
  • Undefined Reference: If you use a reference (@&ingredient) but that item hasn’t been declared previously in the recipe, the compiler warns UNDEFINED_REFERENCE.
  • Database Missing: If you compile with a database and the @ingredient is not found, it warns MISSING_INGREDIENT.
  • Missing Macros: If the database lacks nutritional information for the @ingredient, it warns MISSING_MACROS.
  • Unknown Mass: If it cannot convert a volume or count into grams to estimate nutrition, it warns UNKNOWN_MASS.