Open-source project
clarklab/chowdown avatar
clarklab/chowdown

Chowdown keeps the whole recipe database in a folder of Markdown files

Simple recipes in Markdown format

671 stars202 forksHTMLUnlicense

At a glance

What is it?
Chowdown is a Jekyll site that stores every recipe as a Markdown file in a _recipes collection, with component recipes for combining dishes and a docker-compose setup that keeps content outside the git checkout.
Who is it for?
Chowdown suits people who already live in the terminal and want their recipes as plain files they can diff, back up and edit in any text editor; it is the wrong tool for anyone who wants a phone app, shared accounts, or a hosted cooking site with search and comments.
Can I use it commercially?
Yes. Unlicense is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 83 days ago.
What is it written in?
Mainly HTML, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A recipe site where the database is a directory

Chowdown describes itself as "a simple, plaintext recipe database for hackers", and that phrase sets the whole scope of the project. There is no admin panel, no account system, no image uploader and no hosted service to sign up for. The recipe data is a set of Markdown files kept in the repository, and the site that displays them is generated by Jekyll, the static site generator. The project describes itself as a Jekyll build in its setup notes, the default branch is named gh-pages, and the public site lives at chowdown.io.

The top-level layout makes the scope plain. Alongside the conventional Jekyll folders such as _layouts, _includes, _data and _posts, there is a _recipes folder for the recipe collection and a _components folder for the smaller recipes that other dishes are assembled from. There are also top-level files named recipes.json, search.json, manifest.json, serviceworker.js and trmnl.json, alongside an index.html, a blog.html and a search.html. The listing shows a site that serves more than a single page layout, and that ships a set of data files next to the pages.

For the intended user, the appeal is that the database is inert text. A recipe is a file you can open in any editor, diff in git, or copy to a flash drive. Nothing about the format requires a running application, so the whole collection can be read, searched with ordinary file tools, or rewritten by scripts if that becomes useful later. What you give up for that portability is everything a hosted cooking platform provides: no comment threads, no pantry features, no shopping list generation, and no built-in serving scaler. The project documentation describes none of those, and the file layout does not hint at where they would live.

Getting the site running on port 4000

The installation path is a Jekyll build, and the README names Jekyll as the prerequisite. If the gems are not on the machine yet, the documented command installs the bundler and jekyll gems:

bash
gem install bundler jekyll

You can check whether the toolchain is already present before installing anything:

bash
jekyll -v

After that, the instructions are to clone or download the repository, move into the folder and start the build:

bash
jekyll serve

With default settings, the README says the site is reachable locally at `http://127.0.0.1:4000/`. That is the whole loop: a local web server serving a generated copy of the collection. The project ships no binary, no package published to a registry, and no release artifacts, so there is nothing else to install. The generated output itself is a normal Jekyll build directory, and the source of truth remains the Markdown files in the repository.

One practical note on this path is that the setup notes mention no Gemfile and no bundle install step, even though the setup command installs bundler as well. It also does not document plugin installation for the plugins folder that appears in the repository listing, nor does it say which Jekyll version the layout expects. Those details are left to the reader, and they matter if the recipe layout or the search page fails to render on a newer Ruby and Jekyll combination.

The Recipes collection and its frontmatter contract

Recipes live in the collection named Recipes, which maps to the /_recipes folder. Each recipe is a Markdown document whose frontmatter carries the structured fields and whose body carries the prose. The README lists what the frontmatter contains: Title, Image, and Layout, where Layout is set to "recipe", plus two lists, Ingredients for the things that go into the dish and Directions for the steps. Body content is optional in practice and is where intros and stories go, which is the one place the format allows for a blog-like voice.

The contract is therefore short and entirely convention based. There is no schema file, no validation step and no editor that will tell you a field is missing. If the Layout value is not exactly "recipe", the recipe page will not use the recipe template, and if Ingredients or Directions are absent, the template will render an empty section rather than an error. Nothing documents a required field order, a photo size or a way to declare servings or times, so anything beyond the four listed areas and the body has to be added by editing the layout yourself.

Because the fields are plain YAML in a Markdown file, editing a recipe needs no special tool. A Markdown cheatsheet is linked for people who want the syntax reference, which suggests the intended audience is comfortable with the format already and only needs a reminder of the basics.

Component recipes let one dish borrow another

The one structural idea beyond plain Markdown files is the component recipe, a dish assembled out of other recipes. The README describes the procedure in three steps. The smaller, single recipes are placed into the /_components folder. A new recipe is created as normal in the /_recipes folder. In the frontmatter of that new recipe, you include the recipes from the /_components folder instead of the usual Ingredients list.

That last point is the mechanism worth understanding, because it is not a reference field with a separate label. The parent recipe reuses the Ingredients slot to point at component recipes, so the template decides how to render them. A component file is still a recipe, with the same Title, Image and Layout frontmatter, but it is stored somewhere else and pulled in by name.

The project points at a worked example: the Red Berry Tart recipe, with a link to the raw Markdown of that file and a link to the rendered recipe page on chowdown.io. Comparing those two links is the fastest way to see how the frontmatter is expected to look, since the rule is written out in prose but no complete component recipe snippet is printed. Anyone adopting Chowdown for pastry or batch cooking should start there, because the exact syntax of the component list is defined by the template rather than by the documentation.

The compose file keeps recipe data out of the checkout

The repository also includes a docker-compose.yml, which is the more interesting deployment option because it separates the site code from the content. It defines a single service named chowdown, built from the jekyll/jekyll image, with restart set to always and the container name chowdown. The service command and the port mapping are:

yaml
command: jekyll serve --force_polling
ports:
  - "80:4000"

The command line runs the same generator as the local instructions, but with --force_polling, which suits a bind mounted source tree that changes on the host. The port mapping publishes the container on host port 80 while the container serves on 4000, so the compose deployment and the plain `jekyll serve` workflow expose the site on different host ports.

The volume list is where the content separation becomes explicit. The repository itself is mounted at /srv/jekyll, and four host directories are then mounted over individual collection paths: components, images, posts and recipes, each rooted under /opt/docker/chowdown/data. That means recipe files can live on a data volume while the code stays in git, and edits on the host trigger a rebuild. One inconsistency is worth checking before you rely on it. The compose file mounts a host directory at /srv/jekyll/_images, while the top-level repository listing shows a differently spelled images folder. Whoever sets this up should confirm which path the layout actually reads, because a mismatch here shows up as missing images rather than as an error.

No releases, one branch, an Unlicense

Chowdown has no GitHub releases, so there is no version to pin, no changelog to read before upgrading and no packaged artifact to download. Upgrading means pulling the repository and dealing with whatever the layout changes bring. The last push was on 2026-08-01, and the repository is not archived, so the work is still visible in the history even though no tagged version marks a stable point.

The licence is Unlicense, which is about as permissive as a licence gets: the project places the work in the public domain as far as copyright law allows. For an adopter that means you can copy the code and the recipe format into your own project without attribution requirements, and you are not obliged to publish changes. Because the recipe files are plain Markdown, that also removes any question about what happens to your own content if you keep the data separate from the code, which is exactly what the compose volume layout is designed for.

Nothing in the repository suggests a plugin registry, a theme system or a public API for the recipe data. The JSON files at the top level are part of the built site rather than a documented service contract, so anyone planning to build a second application on top of the collection is working outside what the documentation supports.

Editorial conclusion

Chowdown suits people who already live in the terminal and want their recipes as plain files they can diff, back up and edit in any text editor; it is the wrong tool for anyone who wants a phone app, shared accounts, or a hosted cooking site with search and comments. Before adopting it, check that your Jekyll version builds the recipe layout as you expect, confirm the frontmatter keys Title, Image, Layout, Ingredients and Directions match your own templates, and remember that the project publishes no releases, so upgrading means pulling the git history yourself and the last push was on 2026-08-01.

Frequently asked questions

How do I add a new recipe to Chowdown?

Add a Markdown file to the /_recipes folder. The frontmatter should carry Title, Image and Layout, with Layout set to "recipe", plus an Ingredients list and a Directions list, and the body text is where you put an intro or story.

Can I run Chowdown without installing Ruby and Jekyll locally?

Yes, the repository includes a docker-compose.yml that defines a chowdown service from the jekyll/jekyll image. It runs jekyll serve --force_polling, maps host port 80 to container port 4000, and mounts the repository at /srv/jekyll along with separate data directories for components, images, posts and recipes.

How do I combine several recipes into one dish in Chowdown?

Place the smaller single recipes in the /_components folder, then create the parent recipe as normal in /_recipes. In that parent recipe's frontmatter, list the component recipes in place of the usual Ingredients list, as shown by the Red Berry Tart example.

Does Chowdown publish releases I can install a specific version of?

No. The repository has no GitHub releases, and the setup notes describe cloning the repo and running jekyll serve, so there is no tagged version to install and no changelog to review before upgrading.

Official sources

  1. clarklab/chowdown on GitHub
  2. Issues
  3. License: Unlicense
  4. Project website
  5. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/clarklab-chowdown.svg)](https://hysenlabs.com/projects/clarklab-chowdown)

Was this useful?