How to Self-Host Tandoor Recipes: Full-Featured Recipe Manager 2026
TL;DR
Tandoor Recipes (MIT, ~5K GitHub stars, Python/Django) is a feature-rich self-hosted recipe manager with detailed nutritional information. While Mealie focuses on simplicity, Tandoor goes deeper: built-in nutritional database (OpenFoodFacts integration), barcode scanning for ingredients, detailed shopping list with supermarket aisle mapping, and full-text recipe search. If you care about nutrition tracking alongside recipes, Tandoor is the better choice.
Key Takeaways
- Tandoor: MIT, ~5K stars, Python/Django — recipes + nutrition + shopping + barcode scan
- OpenFoodFacts: Integration with the open food database for nutritional info
- Barcode scanning: Scan ingredient barcodes to add to shopping lists
- Supermarket mapping: Map ingredients to your store's aisles for efficient shopping
- Meal planning: Weekly planner with nutritional summary
- Full-text search: Search inside recipes (not just titles)
Tandoor vs Mealie
| Feature | Tandoor | Mealie |
|---|---|---|
| License | MIT | AGPL 3.0 |
| GitHub Stars | ~5K | ~7K |
| UI Complexity | Higher | Simpler |
| Nutrition data | Yes (OpenFoodFacts) | Limited |
| Barcode scan | Yes | No |
| Shopping list | Yes (advanced) | Yes (basic) |
| Supermarket mapping | Yes | No |
| Recipe scraping | Yes | Yes (better) |
| Meal planning | Yes | Yes |
| OCR import | Yes | Yes |
| API | Yes | Yes |
Part 1: Docker Setup
# docker-compose.yml
services:
db_recipes:
restart: always
image: postgres:16-alpine
volumes:
- postgresql_data:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: "${POSTGRES_PASSWORD}"
POSTGRES_USER: djangodb
POSTGRES_DB: djangodb
web_recipes:
image: vabene1111/recipes:latest
container_name: tandoor
restart: always
ports:
- "8080:8080"
volumes:
- staticfiles:/opt/recipes/staticfiles
- mediafiles:/opt/recipes/mediafiles
depends_on:
- db_recipes
environment:
SECRET_KEY: "${SECRET_KEY}" # openssl rand -hex 64
DB_ENGINE: django.db.backends.postgresql
POSTGRES_HOST: db_recipes
POSTGRES_PORT: "5432"
POSTGRES_USER: djangodb
POSTGRES_PASSWORD: "${POSTGRES_PASSWORD}"
POSTGRES_DB: djangodb
ALLOWED_HOSTS: "meals.yourdomain.com"
GUNICORN_MEDIA: "0"
TIMEZONE: "America/Los_Angeles"
ACCOUNT_EMAIL_SUBJECT_PREFIX: "[Tandoor]"
DEBUG: "0"
nginx_recipes:
image: nginx:mainline-alpine
restart: always
ports:
- "80:80"
volumes:
- staticfiles:/static:ro
- mediafiles:/media:ro
- ./nginx/conf.d:/etc/nginx/conf.d:ro
depends_on:
- web_recipes
volumes:
postgresql_data:
staticfiles:
mediafiles:
# nginx/conf.d/recipes.conf
server {
listen 80;
server_name _;
client_max_body_size 16M;
location /static/ {
alias /static/;
}
location /media/ {
alias /media/;
}
location / {
proxy_pass http://web_recipes:8080;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
# Generate secret key:
openssl rand -hex 64
docker compose up -d
Part 2: HTTPS with Caddy
Replace the nginx container with Caddy for automatic HTTPS:
meals.yourdomain.com {
handle /static/* {
file_server {
root /path/to/staticfiles
}
}
handle /media/* {
file_server {
root /path/to/mediafiles
}
}
reverse_proxy web_recipes:8080
}
Or simply proxy through Caddy to the nginx container:
meals.yourdomain.com {
reverse_proxy localhost:80
}
Part 3: Initial Setup
- Visit
https://meals.yourdomain.com - Create admin account
- Admin Panel → Household → Create Your Household
- Invite other users to the household
Part 4: Import Recipes
From URL
- Recipes → + New → Import From URL
- Paste recipe URL
- Tandoor extracts ingredients, instructions, images
- Review and save
Manual Entry
- Recipes → + New → Manual
- Add ingredients (search by name → Tandoor suggests from food database)
- Add steps with photos
- Set servings, time, difficulty
From OCR (Photo)
- Recipes → + → Create From Image
- Upload photo of printed/handwritten recipe
- Tandoor uses OCR to extract text
- Review and correct
Part 5: Nutrition Information
When you add ingredients, Tandoor looks up nutrition data:
- Type ingredient name → Tandoor suggests matches from OpenFoodFacts
- Select the correct product → nutrition data auto-filled
- Recipe shows: calories, protein, carbs, fat per serving
Manual Nutrition Lookup
- Foods → Search or Create Food
- Type name or scan barcode
- Enter or import nutrition data per 100g
Part 6: Shopping Lists
Generate shopping lists from recipes:
- Add to Shopping List from any recipe (adjust servings)
- Multiple recipes → shopping list auto-combines quantities
- Shopping → Lists → My List
Supermarket Mapping
Map ingredients to your supermarket's sections:
- Supermarkets → Create Supermarket
- Add sections: Produce, Dairy, Meat, Canned Goods, Frozen, Bakery
- Foods → Edit Food → assign to supermarket section
Shopping list sorts by supermarket section → efficient shopping path through the store.
Barcode Scanning
- Shopping → Scan Barcode
- Scan product barcode with your phone camera
- Tandoor looks up the product → adds to shopping list
Part 7: Meal Planning
- Meal Plan → Weekly View
- Click any day → Add Recipe
- Set servings (for the family)
- Nutritional summary shown for the week
- Generate Shopping List from the meal plan
Part 8: Recipe Scraping Sites
Tandoor supports 700+ recipe websites including:
- allrecipes.com
- seriouseats.com
- food52.com
- BBC Good Food
- NYT Cooking
- Bon Appétit
- Epicurious
Part 9: API
# Get API token from Settings → API → Create Token
# List recipes:
curl https://meals.yourdomain.com/api/recipe/ \
-H "Authorization: Token YOUR_API_TOKEN"
# Search recipes:
curl "https://meals.yourdomain.com/api/recipe/?query=pasta" \
-H "Authorization: Token YOUR_API_TOKEN"
# Create a shopping list:
curl -X POST https://meals.yourdomain.com/api/shopping-list/ \
-H "Authorization: Token YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"recipes": [{"recipe_id": 42, "servings": 4}]}'
Maintenance
# Update Tandoor:
docker compose pull
docker compose up -d
# Run migrations:
docker exec tandoor python manage.py migrate
# Backup:
# Database:
docker exec db_recipes pg_dump -U djangodb djangodb | gzip \
> tandoor-db-$(date +%Y%m%d).sql.gz
# Media files (uploaded photos):
tar -czf tandoor-media-$(date +%Y%m%d).tar.gz \
$(docker volume inspect tandoor_mediafiles --format '{{.Mountpoint}}')
# Logs:
docker compose logs -f web_recipes
See all open source food and lifestyle tools at OSSAlt.com/categories/lifestyle.