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 (by default ../OpenStoveImages next to the repo, or set RECIPE_IMAGES_DIR), put BLOB_READ_WRITE_TOKEN in .env.local, and run:
pnpm upload:images # upload photos not yet in the store
pnpm upload:images tomato-soup.avif # upload (or replace) specific photos
pnpm upload:images --all # re-upload everything
pnpm upload:images --dry-run # show what would be uploadedPhotos go under the recipes/ Blob prefix. On the first upload, the script prints the PUBLIC_IMAGE_BASE_URL to set.
vercel env pull writes sensitive variables as empty strings, so paste the token into .env.local yourself.
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.