Alexander Klapheke

I’m a data scientist and self-taught coder (Python, R, Haskell) with a background in linguistics and math and over 10 years’ experience explaining technical concepts to laypeople.

How I use org-mode to organize my recipes

1,918 words CC-BY View source

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 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, an organization system for the 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:

After playing with some possible schemes, I settled on the one below.

1 File structure

All my recipes are in the single file Cooking.org, the basic structure of which is below.

The first few lines, starting with #+, make up the file header. The #+STARTUP line defines some settings 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-Tab1 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 and TODO states, 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. 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, 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 could substitute for olive oil cake; but it couldn’t substitute for 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—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.

The second subheading under Notes is Unsorted Recipes, where recipes are automatically placed when added (see below).

Finally, a Settings subheading contains the in-file settings—this must be the last thing in the file. The first line sets the refile 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 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.

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.

2 Recipe structure

The third level is for the recipes themselves. These basically consist of a properties drawer for the metadata, a checklist for the ingredients, and a numbered list 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.

*** 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. This creates a sparse tree, 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—which supports tab completion.

3 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, which allows the quick “capturing” and filing of data from any open file. I keep the following capture template in my ~/.emacs file:

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 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.

4 Final thoughts

The main downside to this system is that there is no easy way to store images. Many recipes have complicated assemblies 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.