Tandoor Recipes

Recipe manager for organizing and planning meals

Recipe Managers ★ 8.6k stars Medium setup AGPL-3.0

Tandoor is a self-hosted application for managing recipes, planning meals, and creating shopping lists. It supports recipe scaling, meal plans, and ingredient-aware grocery lists.

Key features

  • Recipe import and scaling
  • Meal planning calendar
  • Smart shopping lists
  • Cookbook organization

Pros & cons

Strengths

  • Powerful planning features
  • Good multi-user support

Trade-offs

  • Configuration can be complex
  • UI has a learning curve

Tandoor Recipes replaces

Last reviewed Aug 26, 2026 · 780 words

Pick Tandoor if your household plans meals; pick Mealie if you just want a recipe box that looks nice. That is the whole decision, and it explains why Tandoor, with 8,559 stars and a reputation for complexity, keeps winning with the people who use it daily. Its meal-plan calendar, its ingredient-aware shopping list and its multi-user spaces are the reason to accept a 512 MB PostgreSQL deployment and a UI that takes a week to feel natural.

Import works because of schema.org, not magic

Every self-hosted recipe manager imports from the same set of websites because they all read the same thing: the Recipe JSON-LD block that food sites embed for Google. Paste a URL into Tandoor and it parses that block into ingredients, steps, servings and timings. Sites without structured data fall back to a manual mapper where you highlight text and assign it to fields, which works about half the time. Tandoor also imports from Paprika, Mealie, Nextcloud Cookbook, Chowdown and a dozen other formats, so moving in from Paprika is a file upload rather than a weekend of retyping.

The Compose file has one trap: images need a web server

Tandoor runs as a Django app behind gunicorn on port 8080 inside the container, and gunicorn does not serve uploaded media. The official Compose stack adds an nginx sidecar that serves /media and proxies the rest, and the classic first-day bug is recipe images that upload fine and then never display. It is almost always one of two things: the nginx container was dropped in favour of "just expose 8080", or the reverse proxy in front has a different hostname from what Tandoor was told.

services:
  db_recipes:
    image: postgres:16-alpine
    volumes:
      - ./postgresql:/var/lib/postgresql/data
    env_file: .env
  web_recipes:
    image: vabene1111/recipes
    env_file: .env
    volumes:
      - ./staticfiles:/opt/recipes/staticfiles
      - ./mediafiles:/opt/recipes/mediafiles
    depends_on:
      - db_recipes
  nginx_recipes:
    image: nginx:mainline-alpine
    ports:
      - "8080:80"
    volumes:
      - ./nginx-config:/etc/nginx/conf.d:ro
      - ./staticfiles:/static:ro
      - ./mediafiles:/media:ro
    depends_on:
      - web_recipes

The .env needs a long random SECRET_KEY, DB_ENGINE=django.db.backends.postgresql, and the matching POSTGRES_* values on both containers. Keep the nginx container. It costs 5 MB of RAM and removes a whole category of support threads.

Meal plans and shopping lists are the product

Drag a recipe onto a day, set the servings, and Tandoor scales the ingredients and adds them to the shopping list. The list understands that "200 g flour" from Tuesday and "300 g flour" from Thursday are 500 g of one item, groups by supermarket aisle if you tell it the categories, and is usable from a phone while shopping because checked items are synced live. Plans can be shared per space, so one person cooks and another buys, and the plan view can be set to a week or a month depending on how far ahead the household thinks.

None of this is unique on paper. What is unique is how much of it is wired together: the recipe knows its foods, the foods know their shopping category, and the plan knows its servings, so scaling flows through without you touching the list.

Spaces make it a household tool

A space is a separate recipe collection with its own users and permissions. One instance can host your family's space and a friend's, invisible to each other. Registration is disabled by default; you generate invite links from the space settings and hand them out. This is the "good multi-user support" in the catalogue, and it is better than most tools in the recipes category.

The learning curve is a data model

Tandoor separates keywords (tags), foods (a canonical ingredient), units, and books (curated collections), and it creates foods automatically as you import. The first month you will find "chicken breast", "Chicken Breast" and "chicken breasts" as three foods and spend an evening merging them. That is the price of a shopping list that can aggregate; Mealie avoids the chore by not attempting it. Once the ontology is clean the UI stops feeling complex and starts feeling exact.

What I'd do

Deploy the official stack with the nginx sidecar behind Caddy, PostgreSQL with a nightly pg_dump, one space per household. Spend the first weekend importing 30 recipes you actually cook and merging the foods they create. Start planning the following week and let the shopping list do the rest. If after a month you notice you never opened the plan, you are a recipe-box person; export and move to Mealie without guilt. If you did open it, you will not go back.

Compare Tandoor Recipes

9 head-to-head comparisons.

Similar recipe managers apps