---
date: 1593973704
title: 'How I use org-mode to organize my recipes'
---
::: {.epigraph}
Here the Red Queen began again. "Can you answer useful questions?" she
said. "How is bread made?"
"I know *that*!" Alice cried eagerly. "You take some flour---"
"Where do you pick the flower?" the White Queen asked. "In a garden, or
in the hedges?"
"Well, it isn't *picked* at all," Alice explained: "it's *ground*---"
"How many acres of ground?" said the White Queen. "You mustn't leave out
so many things."
:::
Cooking is a major hobby of mine, and for a long time, I kept recipes
either in text files or printed PDFs in a poorly organized folder on my
hard drive. It was hard to find specific recipes (did I file
[horchata](https://www.tastemade.com/shows/thirsty-for/mexican-horchata)
under "Drinks" or "Mexican"?), hard to remember whether I had made a
recipe before (and whether it was any good), and pretty much impossible
to search for complicated things like "recipes without seafood" or
"recipes that take less than an hour". To make things worse, the whole
folder was cluttered with useless infographics and spreadsheets.
I recently discovered [org-mode](https://orgmode.org/), an organization
system for the [Emacs](https://www.gnu.org/software/emacs/) text editor,
and while there is a bit of a learning curve, it is the best
organization tool I've ever used. I took a few days last winter to
wrangle my recipe collection into something manageable. I had the
following criteria for my setup:
- Recipes can easily be copied from websites without adding a lot of
formatting/structure.
- Recipes can be searched or filtered based on common metadata, such
as yield or cooking time.
- There is a space to add "cooking notes", so the next time I make the
recipe I'll remember what happened the first time (say,
substitutions I made or steps that were unclear).
- It is obvious where any particular recipe should be placed.
After playing with some possible schemes, I settled on the one below.
# File structure
All my recipes are in the single file `Cooking.org`, the basic structure
of which is below.
``` {.org-mode}
#+TITLE: Recipes
#+STARTUP: indent align overview
#+TODO: NEVERMADE(n) | HAVEMADE(h@)
#+TAGS: { weekday weekend } { vegetarian seafood } glutenfree breakfast instantpot slowcooker
#+TAGS: { { asian : chinese(c) japanese(j) korean(k) vietnamese(v) } lebanese(l) indian(i) }
* Meals:
** Meats:
** Vegetables, stir-fries, & curries:
** Rice/orzo & grains:
** Pasta & noodles:
** Soups, stews, & casseroles:
** Salads:
** Sandwiches:
** Breakfast eggs & grains:
* Condiments & snacks:
** Pickles & preserves:
** Sauces & toppings:
** Snacks & dips:
* Baked goods:
** Savory breads/rolls:
** Sweet breads/rolls:
** Batters:
** Cakes & tortes:
** Pies, tarts, & cobblers:
** Pastries, custards/curds, & ice cream:
** Cookies:
* Drinks:
** Hot drinks:
** Cold drinks:
* Projects:
** Brewing:
** Dairy:
** Bread & noodles:
** Candy:
* Notes:
** Price book:
** Unsorted recipes:
** Settings:
```
The first few lines, starting with `#+`, make up the file header. The
`#+STARTUP` line defines some
[settings](https://orgmode.org/manual/In_002dbuffer-settings.html#index-_0023_002bSTARTUP)
for when I open the file. The most important is `overview`, which makes
sure only the headings are shown, and not all \~30,000 lines of text.
Unfortunately, this only shows top-level headings. I can use M-2
S-Tab[^1] to see the second-level headings as well, or M-3
S-Tab to see all recipes, although at this point, I have far too
many for the latter to be useful.
I also define [tags](https://orgmode.org/manual/Tags.html) and [TODO
states](https://orgmode.org/manual/TODO-Items.html), the latter of which
let you mark an item as being in any of various states of completion.
The `@` after the `HAVEMADE` state means that when I mark a recipe as
`HAVEMADE`, org should prompt me to [leave a
note](https://orgmode.org/manual/Tracking-TODO-state-changes.html).
Thus, after I make a recipe, I can jot down what went well and what I
should change next time. The tags define ancillary properties of the
recipe---whether it is gluten-free, what part of the world it comes
from---and tags surrounded with curly braces are mutually exclusive,
such as `{ vegetarian seafood }`.
In the body of the file, the recipes are organized into first- and
second-level [headings](https://orgmode.org/manual/Headlines.html),
starting with `*` and `**`, respectively. The tacit rule is that recipes
within a category should substitute for each other---thus,
`Cakes & tortes` is a valid category because [tres leches
cake](https://smittenkitchen.com/2015/12/tres-leches-cake-a-taco-party/)
could substitute for [olive oil
cake](https://www.americastestkitchen.com/recipes/9648-olive-oil-cake);
but it couldn't substitute for [pickled red
onions](https://www.budgetbytes.com/pickled-red-onions/), so it wouldn't
make sense to group them under a `Mexican` heading.
The final top-level heading is `Notes`. The first thing here is a [price
book](https://en.wikipedia.org/wiki/Price_book)---a simple table of
ingredients I buy often, and at which nearby grocery stores they are
cheapest, with the cheapest price in bold.[^2] I also rounded up to the
nearest dime to make mental math easier, and combat stores'
[psychological
tricks](https://en.wikipedia.org/wiki/Psychological_pricing).
``` {.org-mode}
** Price book:
- Rules of thumb:
- Apple/peach/onion :: 1/2lb ($1/ @ $2/lb, $1.50/ @ $3/lb)
- Banana :: 1/3lb (15¢/ @ 50¢/lb)
- Head of garlic :: 1/8lb
- Chicken drumstick :: 7oz
| Food | Trader Joe's | Whole Foods |
|--------------------+--------------+-------------|
| Milk (1/2gal) | *$1.70* | $2.20 |
| Eggs (dozen large) | *$2* | $3 |
| Butter (4 sticks) | *$3* | $3.50 |
| Coffee (12oz) | $4 | $4 |
| Garlic (head) | 70¢ | *~50¢* |
| Lemon | 50¢ | 50¢ |
```
The second subheading under `Notes` is `Unsorted Recipes`, where recipes
are automatically placed when added (see [below](#adding-recipes)).
Finally, a `Settings` subheading contains the [in-file
settings](https://www.gnu.org/software/emacs/manual/html_node/emacs/Specifying-File-Variables.html)---this
must be the last thing in the file. The first line sets the
[refile](https://orgmode.org/manual/Refile-and-Copy.html) targets to the
second-level headings, so recipes can easily be moved between categories
while keeping them at the third heading level. The second line sets
[`org-tags-column`](https://orgmode.org/manual/Setting-tags.html) to
`-105` from the default value of `-77`. I have a lot of tags on recipes,
and this reduces visual clutter by moving them farther to the right.
``` {.org-mode}
** Settings:
# Local variables:
# org-refile-targets: (("~/org/Cooking.org" :level . 2))
# org-tags-column: -105
# End:
```
As a final bonus, this structure makes it easy to see how many recipes I
have: hit M-! to get a shell prompt, then run
`grep '^\*\*\*' Cooking.org | wc -l`{.bash}.
# Recipe structure
The third level is for the recipes themselves. These basically consist
of a [properties
drawer](https://orgmode.org/manual/Property-syntax.html) for the
metadata, a [checklist](https://orgmode.org/manual/Checkboxes.html) for
the ingredients, and a [numbered
list](https://orgmode.org/manual/Plain-lists.html) for the directions.
For example, here is a recipe for marinated eggs: the properties drawer
runs from `:PROPERTIES:` to `:END:`, followed by the ingredients
prepended with `- [ ]`, then the directions and an endnote.
``` {.org-mode}
*** HAVEMADE Japanese Marinated Soft Boiled Egg for Ramen (Ajitsuke Tamago) :weekend:japanese:
:PROPERTIES:
:Author: J. Kenji López-Alt
:Source:
:Sent_by:
:Yield: 6 eggs
:Prep_Time: 0:10
:Cook_Time: 4:00
:Total_Time: 4:10
:Cost:
:Description: Perfectly seasoned soft-boiled eggs for the best homemade ramen.
:URL: https://www.seriouseats.com/recipes/2012/03/ajitsuke-tamago-japanese-marinated-soft-boiled-egg-recipe.html
:Added: [2019-01-03 Thu]
:END:
- [ ] 1 cup water
- [ ] 1 cup sake
- [ ] 1/2 cup soy sauce
- [ ] 1/2 cup mirin
- [ ] 1/2 cup sugar
- [ ] 6 eggs
1. Combine water, sake, soy, mirin, and sugar in a medium bowl and
whisk until sugar is dissolved. Set aside.
2. Bring 2 quarts of water to a boil in a medium saucepan over high
heat. Pierce fat end of each egg with a thumbtack to make a tiny
hole (this prevents them from cracking and eliminates the air
bubble at the end). Carefully lower eggs into water with a wire
mesh spider or slotted spoon. Reduce heat to maintain a bare
simmer. Cook for exactly 6 minutes. Drain hot water and carefully
peel eggs under cold running water (the whites will be quite
delicate).
3. Transfer eggs to a bowl that just barely fits them all. Pour
marinade on top until eggs are covered or just floating. Place a
double-layer of paper towels on top and press down until completely
saturated in liquid to help keep eggs submerged and marinating
evenly. Refrigerate and marinate at least four hours and up to 12.
Discard marinade after 12 hours. Store eggs in a sealed container
in the fridge for up to 3 days. Reheat in ramen soup to serve.
Note: This recipe can be made using leftover broth from chashu pork.
If you have this broth, replace all the ingredients in the marinade
with the broth.
```
The ingredients list is interactive: with the cursor on one of the list
items, I can use `C-c C-c` to check or uncheck it. This is extremely
useful for making shopping lists. The directions list has to be
separated by *two* blank lines from the ingredients list, or org-mode
will parse them as being part of the same list, and insist they both be
bullets or both be numbers.
The properties drawer has slots for most of the metadata that comes with
a recipe: author, yield, estimated time, etc., as well as one for the
URL, and the date it was added to `Cooking.org`. Combined with the tag
structure, it is a breeze to search for recipes by hitting C-c /
m and typing in a [match
pattern](https://orgmode.org/manual/Matching-tags-and-properties.html).
This creates a [sparse
tree](https://orgmode.org/manual/Sparse-Trees.html), which shows the
titles of all matching recipes. For example, I can search for:
- Chinese recipes with the pattern `chinese`;
- Chinese recipes that are *also* vegetarian with
`chinese+vegetarian`;
- Vegetarian Chinese recipes I've never made before with
`chinese+vegetarian/NEVERMADE`;
- Recipes I've added in the past month with `Added>="<-1m>"`, or since
May with `Added>="<2020-05-01>"`;
- Recipes that come together in less than 90 minutes with
`Total_time<"1:30"`;[^3]
- Recipes from the New York Times with `URL={cooking.nytimes.com}`.
The braces indicate a regular expression.
There is also the C-c / p command for simple equality
matches---for example, if I wanted to find all recipes by [Amanda
Hesser](https://en.wikipedia.org/wiki/Amanda_Hesser)---which supports
tab completion.
# Adding recipes
Although adding a new recipe is as easy as creating a new heading, it
would be tedious to copy the properties drawer each time. A much easier
way is to use [capture](https://orgmode.org/manual/Capture.html), which
allows the quick "capturing" and filing of data from any open file. I
keep the following [capture
template](https://orgmode.org/manual/Capture-templates.html) in my
`~/.emacs` file:
``` {.lisp}
(custom-set-variables
'(org-capture-templates
'(("r" "Recipe" entry
(file+headline "~/org/Cooking.org" "Unsorted recipes:")
"* NEVERMADE %? :weekday:
:PROPERTIES:
:Author:
:Source:
:Sent_by:
:Yield:
:Prep_Time:
:Cook_Time:
:Total_Time:
:Cost:
:Description:
:URL:
:Added: %u
:END:"))))
```
I can add a recipe from any file by hitting C-c c r; org-mode
will create a new recipe under `Unsorted Recipes` with the template
above, and I just have to fill in the details. The `%u` is
[automatically
replaced](https://orgmode.org/manual/Template-expansion.html) with the
current date, and the `%?` tells org-mode where to put the cursor. Since
most recipes follow the same basic pattern (paragraph of metadata,
unnumbered list of ingredients, numbered list of directions), formatting
the recipes as described above is very quick, with a few caveats: times
have to be formatted as `HH:MM`, and the description can't run into
multiple paragraphs (I use `//` as a paragraph separator, but I'm not
thrilled with this solution).
Finally, the new recipe can be easily refiled with C-c C-w.
# Final thoughts
The main downside to this system is that there is no easy way to store
images. Many recipes have [complicated
assemblies](https://smittenkitchen.com/2012/03/potato-knish-two-ways/)
that are best explained in pictures. The best I can do is store a note
that says something like "see pictures in original recipe", which has
been good enough so far.
[^1]: In Emacs-speak, C is the control key, M, or
"meta" is alt, and S is shift. So M-2 S-Tab
means you hit alt-2, then shift-tab in sequence.
[^2]: This is just a subset for illustration; my actual table is larger.
[^3]: In this and the above example, notice the quotation marks.