DEV Community

Cover image for I Built a Free Ingredient Substitution Finder with Astro and Zero JavaScript
meet dhanani
meet dhanani

Posted on

I Built a Free Ingredient Substitution Finder with Astro and Zero JavaScript

Last month I shipped IngredientReplace - a free tool that helps home cooks find ingredient substitutes with exact ratios. It covers 100+ ingredients, 500+ tested alternatives, and loads in under 1 second on mobile.

The entire site is statically generated with Astro. Zero client-side JavaScript for the core experience. Here's how I built it and what I learned.

The Problem
Every time you Google "substitute for buttermilk," you get a 2,000-word blog post about someone's childhood before the actual answer. I wanted a tool that gives you the substitute, the ratio, and the dietary info instantly.

Why Astro
I chose Astro for three reasons:

  1. Static output = fast. Every page is pre-rendered HTML. No hydration, no framework runtime, no loading spinners. Google rewards fast sites with better rankings.

  2. Component-based DX. I still get reusable .astro components with scoped styles and props. It feels like React but ships zero JS to the browser.

  3. Built-in SEO features. Sitemap generation, RSS, canonical URLs, and easy structured data injection are all straightforward.

Architecture

src/
├── data/
│   ├── ingredients.json      # 100+ ingredients with substitutes
│   ├── categories.json       # Groupings (dairy, eggs, flour, etc.)
│   └── context-pages.json    # Recipe-specific substitution pages
├── pages/
│   ├── index.astro
│   ├── substitute/[...slug].astro   # Dynamic routes
│   ├── sitemap.xml.ts
│   └── robots.txt.ts
├── components/
│   ├── SearchBar.astro
│   ├── SubstituteList.astro
│   └── SEOHead.astro
└── layouts/
    └── BaseLayout.astro
Enter fullscreen mode Exit fullscreen mode

The data lives in JSON files. Each ingredient has this shape:

{
  "slug": "buttermilk",
  "name": "Buttermilk",
  "substitutes": [
    {
      "name": "Milk + Lemon Juice",
      "ratio": "1 tbsp lemon juice + milk to fill 1 cup",
      "vegan": false,
      "glutenFree": true,
      "notes": "Let sit 5 minutes before using"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

SEO Strategy That Actually Worked
The site went from 0 to indexed on 200+ pages within 3 weeks. Here's what mattered:

Every substitute page includes FAQPage and BreadcrumbList JSON-LD schemas. Google uses these for rich results:

const faqJsonLd = JSON.stringify({
  '@context': 'https://schema.org',
  '@type': 'FAQPage',
  mainEntity: faqs.map(faq => ({
    '@type': 'Question',
    name: faq.question,
    acceptedAnswer: {
      '@type': 'Answer',
      text: faq.answer,
    },
  })),
});
Enter fullscreen mode Exit fullscreen mode

The Search Feature Without a Backend
The search bar works without any API calls. At build time, I generate a lightweight search index as a static JSON file. The client-side search loads this index on first interaction (not on page load) and filters locally:

// Only loads when user focuses the search input
const response = await fetch('/search-index.json');
const index = await response.json();
Enter fullscreen mode Exit fullscreen mode

This keeps the initial page load at zero JS while still providing instant search results after the first keystroke.

Deployment
The site runs on Cloudflare Pages:

  • Free tier handles the traffic easily
  • Global CDN means sub-100ms TTFB worldwide
  • Automatic deployments on git push
  • Custom headers for caching and security
  • Build time for 200+ pages is under 10 seconds.

Results After 4 Weeks

  • 200+ pages indexed by Google
  • Multiple pages appearing in "People Also Ask" featured snippets
  • Sub-1-second load times on mobile (3G)
  • Zero hosting cost

Key Takeaways
Static sites still win for content-heavy tools. If your data doesn't change every minute, pre-render it.

Astro's zero-JS default is a superpower for SEO. Less JavaScript means faster pages means better rankings.

Structured data gets you rich results fast. FAQ schema and BreadcrumbList schema are low-effort, high-reward.

JSON data files are underrated. You don't need a CMS or database for a tool with a few hundred entries. A JSON file in your repo is simpler, faster, and version-controlled.

Build the thing people are Googling. "Substitute for X" gets searched millions of times per month. Building a tool that answers that query directly is more effective than writing blog posts about it.

Try It
Check out IngredientReplace if you want to see the final result. It's free, no login, and works on any device.

If you're building a similar content-heavy static site with Astro, happy to answer questions in the comments.

Top comments (0)