why

Why go through all the trouble?

Simply put, I love plants and I love animals. I lost count of the times I stood in a plant nursery googling whether something was safe to bring home to our little Pandora, or 🐼 for short.

A very cute cat.
A very cute cat.
A very cute cat.

It's as simple as that?

That was the idea, at least. I just wanted a single place that had all the information I needed so I could make informed purchasing decisions. I also figured I couldn't possibly be the only person who has this problem. So, I set off to make this project during the holiday break of 2022.

However, I didn't want to make it too easy for myself...

A challenge!

I'm a platform engineer by trade. I have plenty of smarts when it comes to the technical side of hosting and running things, but it's been years since I've done any front-end work. Career-wise, I need to be able to speak the same language as teams I have to support. So, understanding how far behind that portion of my skillset had become, I thought this would be the perfect opportunity to brush up.

The Requirements:

  • Must keep operational costs as close to zero as possible. The only money I've put down on this so far is the $20 AUD to purchase the domain name.
  • Must be hosted on Cloudflare Pages. I could've chosen GitHub Pages to keep everything in one place, but automated Cloudflare builds & deployments work out-of-the-box with minimal configuration. Besides, I've already worked with the latter and I wanted the challenge of trying something new.
  • Must be completely static. There should be no server-side rendering, processing or other explicit backend dependencies to manage. These days Hugo does the honours, rendering the entire site to flat files at build time.
  • All data must be served statically as well. The entirety of the data set is contained within a single JSON file, which you can view at /api/plants.json. This is the source of truth for all derivative data sets and lookup tables used on this site. It's effectively what I call a "dumb API". Check out the API documentation if you'd like to know more about it.
  • Must use SvelteKit, TypeScript, TailwindCSS and Vite. I had zero working knowledge of any of these and my front-end peers can't seem to shut up about them. So... why not?
  • Must be fast. Everything is static, compressed, cached and sitting behind a world-class CDN. In the past I worked for a network performance and load testing SaaS for close to 5 years. I wouldn't be able to look myself in the mirror if I couldn't easily do this one. 😅
  • Must be open and forever-free. The openness lives in the data. The entire database is a free, unrestricted public API that anyone can download and use for their own projects without any strings attached. And if you spot something wrong or missing, corrections are always welcome! Check how to contribute or see the latest changes.

So far, it's going quite well. I haven't had any issues with meeting any of these self-imposed development constraints.

Round two!

That was 2022. The funny thing about a frontend toolchain is that it ages like fine milk. By the time I came back to give the site a fresh coat of paint, the build didn't even run anymore. So in 2026 the site got the full revamp treatment. SvelteKit, TypeScript, TailwindCSS and Vite are out and Hugo is in.

The new rules are even stricter than before. One binary builds the entire site. There are zero dependencies to install, one hand-written stylesheet and a few small scripts of delicious vanilla JavaScript. Builds run on my own CI in the homelab and the finished files are uploaded straight to Cloudflare Pages. If I disappear for another two years, the site will build exactly the same the day I come back.

A very cute cat.
A very cute cat.
A very cute cat.

Where did you source all this data?

There are quite a few sources I've collated from, but these are the main ones:

  1. iNaturalist is the best source of high-quality, community-driven Creative Commons license photography. All images have been sourced from this site along with licensing and attribution data.
  2. ASPCA was used to initially prime the first dataset. This is also where I sourced most of the common name and symptom data. Every record now carries a source: the ASPCA page for the plant, the Colorado State University Guide to Poisonous Plants, or both. A plant that neither source names is not listed.
  3. Wikipedia is the best source of scientific classification data out there. It also supplies the plant descriptions and the toxicity notes on each plant page.
  4. Wikidata connects each plant to its records in the other databases. One identifier lookup opens the door to everything below.
  5. GBIF, the Global Biodiversity Information Facility, supplies extra vernacular names, native ranges and the countries where each plant is observed in the wild.
  6. The USDA PLANTS database supplies the duration and growth habit facts.

All of this disparate data was collated and munged together by several processing scripts written in Go as Magefiles. It got me about 95% there, but it still needed quite a bit of handraulic finessing. Those scripts have since retired. Hugo now derives every dataset and lookup table straight from the primary database on each build.

Where to go from here?

Four years in, I think the little site has earned its keep. It now answers the happier question too, with a list of plants that are actually safe to bring home. It also works the problem backwards with the symptom finder for when you don't know what your gremlin just ate. The dataset keeps getting scrubbed, deduplicated and fattened up with proper descriptions.

The plan from here is more of the same. Adding more species, cleaner data and keeping the whole thing fast, free and boring to operate.

I sincerely hope you find Plant🌱Smart as useful as I had fun making it.