OpenStove is a curated collection of community-crafted recipes – no ads, no fees, just a love for food and shared knowledge. Browse it live at openstove.org.
Application code and recipe text live in this public repository. Recipes are Markdown files managed through Astro content collections, while recipe photographs are stored separately in Vercel Blob so licensed image files stay out of the public Git history.
- Community-maintained Markdown recipes
- Search, tags, pagination, and browser-local bookmarks
- Ingredient scaling
- Print-friendly recipe pages and browser PDF export
- Public recipe contribution form with GitHub Issue review
- Keystatic CMS for maintainers
- Recipe images delivered through Vercel Blob
- Responsive light and dark themes
- Astro 7 with server rendering
- Tailwind CSS 4
- TypeScript
- Keystatic for Git-backed content editing
- Vercel for hosting and serverless routes
- Vercel Blob for recipe photographs
- GitHub Issues for form submissions
- Cloudflare Turnstile for optional spam protection
src/
├── components/ Reusable Astro components
├── content/recipes/ Markdown recipe collection
├── images/ Public UI illustrations and fallback image
├── layouts/ Shared page layouts
├── lib/ Image and contribution utilities
├── pages/ Pages and server API routes
└── styles/ Tailwind v4 global styles
keystatic.config.ts Maintainer CMS schema
scripts/ Maintainer utilities
vercel.json Production headers and CSP
git clone https://github.com/mearashadowfax/OpenStove.git
cd OpenStove
pnpm install
cp .env.example .env
pnpm devAvailable scripts:
pnpm dev # Start the local server with hot reloading
pnpm build # Type-check and create the production server build
pnpm preview # Serve the production build locally
pnpm test # Run the test suite
pnpm format:check # Check formatting
pnpm format:fix # Apply formattingFor other Astro CLI commands, see Astro's CLI documentation.
Recipes live in src/content/recipes and are validated by src/content.config.ts. The Markdown filename is the recipe ID and URL path – do not add a separate slug field to recipe frontmatter:
src/content/recipes/creamy-tomato-soup.md
→ /recipes/creamy-tomato-soup
Recipe photographs are publicly readable from Vercel Blob, but their source files are kept out of this repository for licensing reasons. Frontmatter stores only the Blob filename:
image: 'tomato-soup.avif'
imageAlt: 'A bowl of creamy tomato soup'The application combines the filename with PUBLIC_IMAGE_BASE_URL. Without that variable (e.g. in a fresh local setup), or when an image is unavailable, recipe pages display the repository's fallback image.
To upload photographs, keep the originals in a private local or backed-up directory and run:
BLOB_READ_WRITE_TOKEN=vercel_blob_... \
pnpm upload:images --dir /path/to/private-recipe-imagesThe script uploads AVIF files under the recipes/ Blob prefix without random suffixes and prints the required PUBLIC_IMAGE_BASE_URL.
Never commit recipe photographs or Blob write tokens to this repository.
There are two supported workflows:
- Use the online contribution form. It creates a GitHub Issue containing generated Markdown for maintainer review.
- Follow
CONTRIBUTING.mdand open a pull request.
The contribution API requires:
GITHUB_TOKEN Fine-grained PAT with Issues: read and write
GITHUB_REPO mearashadowfax/OpenStove
Cloudflare Turnstile is supported through PUBLIC_TURNSTILE_SITE_KEY and TURNSTILE_SECRET_KEY.
Maintainers can edit recipe Markdown through Keystatic:
- Local: run
pnpm devand open http://127.0.0.1:4321/keystatic. Local mode reads and writes the working tree directly. - Production: uses GitHub authentication; only users with write access to the OpenStove repository can make changes.
- Import this repository into Vercel.
- Connect a public-read Vercel Blob store.
- Upload recipe AVIFs and set
PUBLIC_IMAGE_BASE_URL. - Configure the contribution and Keystatic environment variables.
- Deploy the
mainbranch. - Verify recipe images,
/contribute,/keystatic, and print/PDF output.
See .env.example for the complete environment variable list.
OpenStove code and recipe text are licensed under CC BY-NC-SA 4.0 – see the full license for details. Recipe photographs are not included in this repository and are licensed separately.