πŸ€– FIGH /fΚ²Ιͺ/ β€” Irish, β€œweaves”

Templates you didn't write, running safely.

figh renders templates written by people you don't control β€” customers, tenants, anyone with a text box. It escapes by default, it cannot loop forever, it cannot reach your filesystem, and it renders identically on a server and in a browser. Not by convention. By construction.

See it Source on GitHub

What it looks like

<h1>{{ event.name }}</h1>

<f-if test="tickets.size > 0">
  <ul>
    <f-for each="t in tickets">
      <li>{{ t.name }} β€” {{ t.price_cents | money: 'eur' }}</li>
    </f-for>
  </ul>
<f-else/>
  <p>{{ 'public.event.sold_out' | t }}</p>
</f-if>

Two things to scan for and no more: {{ … }} puts a value in, <f-…> is a directive. Everything else is copied through untouched β€” figh never parses your HTML.

What it refuses to do

Why not Liquid

Liquid is the obvious answer and it nearly was ours. Three things sent us the other way.

figh is smaller than Liquid on purpose. No assign, no capture, no arithmetic, fourteen filters. If a template needs to compute something, that belongs in the data you pass it β€” where you can test it.

The name

figh is Irish for weaves β€” from Old Irish figid, from Proto-Celtic *wegyeti, the same root that gives English weft. It's pronounced roughly fee; the gh is silent. It was called weft until we discovered how many things already are.