Recipe Format: How to Write, Structure & Store Recipes Properly

Your recipes are probably in at least five places right now. A folder of screenshots. Browser bookmarks you've never revisited. A recipe app from 2019. A notes file with no structure. A stack of index cards. Maybe a shared Google Doc that stopped being updated.

None of these formats talk to each other. None let you generate a shopping list automatically. And if the app shuts down, the recipes are gone.

The format problem is worth solving properly. Here's how.

What Makes a Good Recipe Format

Before comparing formats, it helps to know what you're optimizing for. A good recipe format does four things:

Structured ingredients. Each ingredient should have a name, a quantity, and a unit — as separate fields, not a blob of text. "400g canned tomatoes" needs to be parsed as name=canned tomatoes, quantity=400, unit=g. Without that separation, you can't generate a shopping list, scale a recipe, or calculate nutrition.

Clear, sequential steps. Instructions should be ordered and unambiguous. The best formats tie ingredients directly to the steps where they're used, so you don't have to cross-reference an ingredients list while cooking.

Metadata. Servings, prep time, cook time, source URL, tags. This is how you filter a collection ("what's quick and vegetarian?") and scale correctly.

Portability. The format should be readable without special software and transferable between tools. A format that only works in one app is a liability.

Most recipe formats are good at one or two of these. Few are good at all four.

Common Recipe Formats

Plain text and Markdown — the most common "format" for personal recipe collections. Easy to write, readable everywhere, syncs fine. The problem: there's no structure. A computer can't reliably extract ingredients from a Markdown bullet list because everyone formats them differently. No automated shopping lists. No scaling. Just text.

App databases — Paprika, Mealie, Tandoor, and dozens of others store recipes in proprietary formats. Good interfaces, some automation. The problem: you're locked in. Exporting is painful, importing from other apps is worse, and if the project dies, your recipes die with it.

Schema.org JSON-LD — the format behind recipe rich snippets in Google search results. Machine-readable by design. The problem: nobody writes recipes in JSON. It's generated by CMS plugins, not humans. And even though it's "structured," ingredients are still stored as free-text strings, not parsed quantities.

Handwritten cards and PDFs — completely portable, completely unprocessable. Great for heirlooms, useless for automation.

See the full format comparison for side-by-side examples of the same recipe in each format.

The Standard Recipe Format Problem

There is no universal standard for digital recipes. That's not an oversight — it's the result of competing incentives.

Professional kitchens have standardized recipes: a fixed format with precise quantities, yields, cooking methods, and plating instructions. This exists because consistency matters — the same dish needs to taste the same every night regardless of which cook prepares it. Standardization is how you scale a kitchen without chaos.

Digital recipes have the opposite incentive. Recipe websites make money from traffic. A recipe format that lets software extract your content and use it elsewhere works against their business model. Schema.org JSON-LD exists because Google pushed it for SEO purposes, not because recipe sites wanted interoperability.

So we have a fragment of a standard (JSON-LD for the web), a lot of proprietary formats, and nothing that works well for personal recipe management. The result is that individuals are left cobbling together their own systems — usually involving some combination of bookmarks, screenshots, and apps that don't sync with each other.

Cooklang: A Recipe Format That's Both Human and Machine Readable

Cooklang is a plain text recipe format that solves both sides of the problem. Recipes read naturally as prose. But three annotations make the text machine-parseable:

  • @ingredient{quantity%unit} — marks ingredients with structured quantity and unit
  • #cookware{} — marks pots, pans, and tools
  • ~{time%unit} — marks timers

Here's a chicken stir-fry in Cooklang:

---
servings: 2
time: 25 minutes
tags: [quick, weeknight]
---

Slice @chicken breast{400%g} into thin strips. Toss with @soy sauce{1%tbsp} and @cornstarch{1%tsp}. Set aside.

Heat @sesame oil{1%tbsp} in a #wok{} over high heat until smoking.

Add chicken and stir-fry for ~{3%minutes} until browned. Remove and set aside.

Add @garlic{3%cloves}, minced, and @ginger{1%tsp}, grated. Cook ~{30%seconds}.

Add @broccoli{200%g}, @bell pepper{1}, sliced, and @snap peas{100%g}. Stir-fry ~{4%minutes} until tender-crisp.

Return chicken to the wok. Add @oyster sauce{2%tbsp} and @rice vinegar{1%tbsp}. Toss ~{1%minute} to coat.

Serve over @jasmine rice{300%g}, cooked.

You can read this the way you'd read any recipe. But a parser also knows that this recipe requires 400g chicken breast, 200g broccoli, and six other ingredients — as structured data, not a text string.

From this single file, tools can:

  • Generate a shopping list (alone or combined with other recipes for the week)
  • Scale all quantities to 4 servings with a single flag
  • Run step-by-step timers (3 minutes, 30 seconds, 4 minutes, 1 minute)
  • Display the recipe in a readable format without the markup showing
  • Search your collection by ingredient or tag

This is what the format comparison post calls the "fundamental tension" — plain text is human-readable but not machine-parseable; JSON is machine-readable but not human-writable. Cooklang is both, because the annotations stay out of the way when you're reading.

If you want to understand the theory behind why this matters, why we built a recipe standard goes into the broader argument.

Storing Recipes as Files

Cooklang recipes are .cook files — plain text with a different extension. They work with everything that works with files.

Folder structure. Organize recipes however your brain works. By cuisine, by meal type, by occasion, by how often you make them — it doesn't matter because you're not locked into anyone else's taxonomy.

recipes/
├── weeknight/
│   ├── chicken-stir-fry.cook
│   ├── pasta-aglio-e-olio.cook
│   └── sheet-pan-salmon.cook
├── weekend/
│   ├── beef-bourguignon.cook
│   └── sourdough.cook
└── baking/
    ├── banana-bread.cook
    └── chocolate-chip-cookies.cook

Sync. Put the folder in iCloud Drive, Dropbox, or Google Drive. The mobile app reads directly from iCloud. The CLI reads from wherever you point it.

Git. If you want version control — and you should, if you develop recipes over time — a Git repo lets you track every change. You can see exactly when you reduced the salt, what happened when you tried a different technique, and roll back experiments that didn't work. The post on recipes as code covers this in more detail.

git log --oneline chicken-stir-fry.cook
# d4e221b swap oyster sauce for hoisin, reduce soy
# 8b3f9a2 add cornstarch to marinade
# 1c7d4f1 initial recipe

Longevity. Plain text files from 1985 are still readable today. An app from 2019 might not be. Your recipe collection is worth keeping in a format that doesn't depend on any company staying in business.

Getting Started

The fastest path is to take one recipe you make often and write it in Cooklang format. It takes about five minutes. Save it as recipe-name.cook. Then install CookCLI and run:

cook recipe chicken-stir-fry.cook

You'll see the recipe displayed cleanly, with a separate ingredients section parsed automatically. Run it with --servings 4 and the quantities adjust. Run cook shopping-list across multiple recipes and you get a combined list.

The getting started guide walks through setup step by step. If you prefer a visual introduction, the language spec is short — Cooklang has three annotations, not thirty.

One format. Plain text. Readable by humans and machines. That's the whole idea.

Start with the getting started guide →

-Alex