OpenStove is a community recipe site where every recipe is a Markdown file in this repository. Readers get recipes with no ads, no fees, and no account – just the dish, scalable to any number of servings. Contributors add a recipe with a form or a pull request, and because both the code and the recipe text are open, anyone can fork the whole site and run their own.
Browse it live at openstove.org.
- Open content. 80+ recipes, licensed under CC BY-NC-SA 4.0, each one a plain Markdown file you can copy, edit, or fork.
- No account needed. Bookmarks are stored in your browser only. Nothing to sign up for, nothing tracked.
- Cooks for any table. A servings stepper scales every quantity, and a US / metric toggle converts cups, pounds and ounces to grams and millilitres.
- Two ways to contribute. A web form that needs no Git knowledge, or a pull request for a Markdown file. Both are reviewed by maintainers on GitHub.
- Print-ready. Every recipe page prints cleanly and exports to PDF from the browser.
- Built to fork. Astro, Tailwind CSS, Keystatic CMS and Vercel. Clone,
pnpm dev, and you have a working recipe site.
A recipe is one file. Its name is its URL:
# src/content/recipes/creamy-tomato-soup.md → openstove.org/recipes/creamy-tomato-soup
---
title: 'Creamy tomato soup'
cookingTime: 40
ingredients:
- items:
- { quantity: '2', unit: 'cup', name: 'vegetable broth' }
- { quantity: '1/4', unit: 'cup', name: 'heavy cream' }
steps:
- actions: ['Simmer for 25 minutes, then blend until smooth.']
tags: ['soup', 'vegetarian']
---- Getting started
- Contributing a recipe
- Recipe format
- Recipe photos
- Editing with Keystatic
- Deploying your own
- Project structure
- Built with
- License
You need Node.js 22.12 or newer and pnpm.
git clone https://github.com/mearashadowfax/OpenStove.git
cd OpenStove
pnpm install
cp .env.example .env
pnpm devOpen http://localhost:4321. The site runs fully without any environment variables: recipe pages show a placeholder photo, and the contribute form is disabled until you add GitHub credentials (see Deploying your own).
Other scripts:
pnpm build # Type-check and create the production build
pnpm preview # Serve the production build locally
pnpm test # Run the test suite
pnpm format:check # Check formatting
pnpm format:fix # Apply formattingNo Git? Use the contribution form. It opens a GitHub Issue with the generated Markdown, which maintainers review and merge.
Prefer a pull request? Add a file to src/content/recipes/ and open a PR. The full guide, including the recipe template and naming rules, is in CONTRIBUTING.md.
Recipe text you contribute is licensed under CC BY-NC-SA 4.0, like the rest of the project. Photo rights stay with you unless you grant them explicitly.
Recipes live in src/content/recipes and are validated against the schema in src/content.config.ts at build time. The frontmatter is the recipe; the Markdown body is unused.
The filename is the recipe ID and URL path, so do not add a slug field to the frontmatter.
Key rules:
- Quantities are numbers only.
'1/2','1.5','1 1/2'and'3-4'are valid;'125g'is rejected. Put the unit inunit. - Scaling. By default a recipe is written for one serving and readers get a stepper. For a whole dish (cake, pie, loaf) set
servings: 8andscalable: false; readers then see "Serves 8". - Tags. Lowercase, up to three, each one gets its own page.
- Long titles. Cards clamp titles to two lines. If the full title is long, add an optional
cardTitlefor the card; the recipe page keepstitle.
A blank copy with no placeholders is in Ready-to-go-Template.md.
Photos are not in this repository. They are served from Vercel Blob so licensed image files stay out of the public Git history. Frontmatter stores only the filename:
image: 'tomato-soup.avif'
imageAlt: 'A bowl of creamy tomato soup'The site prepends PUBLIC_IMAGE_BASE_URL to that filename. Without the variable, or when a photo is missing, the page shows the fallback image from public/placeholder-recipe.png.
To upload photos, keep the originals in a private directory and run:
BLOB_READ_WRITE_TOKEN=vercel_blob_... \
pnpm upload:images --dir /path/to/private-recipe-imagesThe script uploads every .avif under the recipes/ Blob prefix and prints the PUBLIC_IMAGE_BASE_URL to set.
Never commit recipe photos or Blob write tokens to this repository.
Maintainers can edit recipes in a web UI instead of raw YAML:
- Locally: run
pnpm devand open http://127.0.0.1:4321/keystatic. It reads and writes files in your working tree directly. - In production:
/keystaticuses GitHub authentication. Only users with write access to the repository can make changes.
OpenStove is built for Vercel, using server rendering and serverless routes.
- Fork and import this repository into Vercel.
- Create a public-read Vercel Blob store and connect it to the project.
- Upload your recipe photos with
pnpm upload:imagesand setPUBLIC_IMAGE_BASE_URL. - Set the contribute-form variables. All three are required in production:
Locally, Turnstile is waived; only the GitHub variables are needed.
GITHUB_TOKEN Fine-grained PAT with Issues: read and write GITHUB_REPO your-user/your-fork TURNSTILE_SECRET_KEY Cloudflare Turnstile secret (spam protection) PUBLIC_TURNSTILE_SITE_KEY Cloudflare Turnstile site key - Set the Keystatic GitHub-app variables if you want the production CMS.
- Deploy the
mainbranch, then check recipe images,/contribute,/keystaticand print output.
.env.example lists every variable with a comment.
src/
├── components/ Reusable Astro components
├── content/recipes/ Markdown recipe collection
├── images/ UI illustrations
├── layouts/ Shared page layouts
├── lib/ Quantity parsing, scaling, image and contribution utilities
├── pages/ Pages and server API routes
└── styles/ Tailwind v4 global styles
keystatic.config.ts Maintainer CMS schema
scripts/ Photo upload and build utilities
vercel.json Production headers and CSP
- Astro 7 with server rendering
- Tailwind CSS 4
- TypeScript
- Keystatic for Git-backed content editing
- Vercel for hosting and serverless routes, Vercel Blob for photos
- GitHub Issues for form submissions
- Cloudflare Turnstile for spam protection
Code and recipe text are licensed under CC BY-NC-SA 4.0 – see LICENSE. Recipe photographs are not included in this repository and are licensed separately.