Comparing F# HTML DSLs for Rendering long web pages - Falco.Markup vs Giraffe.ViewEngine vs Feliz.ViewEngine

Date: 2024-02-02 | create | tech | fsharp | benchmarks | giraffe | falco | feliz | html |

Last year I started building fullstack web apps with F#. I found the devx of using a single fullstack monoolith to be far superior to multi-monolith, even when that meant losing access to popular SPAs like React, Svelte, and Vue. Building apps with F#, HTMX, and HTML rendered via DSL has been a breath of fresh air for web dev that I didn't know I needed.

There are several popular HTML DSLs to choose from in F#. I've previously focused on using Giraffe.ViewEngine as it performed well in my previous benchmarks and pairs well with F# / Giraffe, the web framework I've used in CloudSeed (my F# project boilerplate) for several years.

But several Fsharpies requested additional benchmarks comparing other HTML DSLs so here we'll be comparing Giraffe.ViewEngine, Falco.Markup, and Feliz.ViewEngine to see how they stack up.

Benchmark Setup

F# HTML DSL - Long, shallow page benchmark

The benchmark builds long, shallow pages.

For this benchmark we build simple HTML pages containing a long list of items in a table, ranging from size 10 to 5000.

We benchmark using BenchmarkDotnet on a free Replit instance.

You can access the code and run the benchmark yourself on Replit: F# HTML DSLs - Long, shallow page benchmark Replit

Results Overview

F# HTML DSLs - long page benchmarks graphed

In general Falco.Markup > Giraffe.ViewEngine > Feliz.ViewEngine. Falco.Markup comes out to ab 5-10% faster than Giraffe.ViewEngine and both are ~5x faster than Feliz.ViewEngine.

The absolute difference in these is on the order of 1-5 ms for pages up to 1000 items and 10s of ms up to 5000 items, so pretty fast all things considered.

Detailed Results

F# HTML DSLs - long page benchmarks data

In this section I'll paste my results from BenchmarkDotnet for posterity.

10 Items

Benchmark - 10 items

  • Falco.Markup: 0.015 ms
  • Giraffe.ViewEngine: 0.016 ms
  • Feliz.ViewEngine: 0.053 ms

100 Items

Benchmark - 100 items

  • Falco.Markup: 0.105 ms
  • Giraffe.ViewEngine: 0.101 ms
  • Feliz.ViewEngine: 0.500 ms

1000 Items

Benchmark - 1000 Items

  • Falco.Markup: 1.354 ms
  • Giraffe.ViewEngine: 1.393 ms
  • Feliz.ViewEngine: 5.957 ms

2000 Items

Benchmark - 2000 Items

  • Falco.Markup: 2.553 ms
  • Giraffe.ViewEngine: 2.921 ms
  • Feliz.ViewEngine: 12.015 ms

5000 Items

Benchmark - 5000 Items

  • Falco.Markup: 6.294 ms
  • Giraffe.ViewEngine: 7.350 ms
  • Feliz.ViewEngine: 32.632 ms

Next

Overall these are all pretty fast. Obvs you need to benchmark with your own code on your own machines to see how it will really perform in production but they all seem to perform reasonably well.

Personally I'd probably opt for Giraffe.ViewEngine or Falco.Markup as they seem to perform best and have a cleaner API in my opinion. That said, all of these DSLs can render to string so it's easy to mix and match with whatever framework you want to use.

If you liked this post, you might also like:

Want more like this?

The best / easiest way to support my work is by subscribing for future updates and sharing with your network.