// stati.config.ts
import { defineConfig } from '@stati/core';
export default defineConfig({
site: { title: 'My site', baseUrl: 'https://example.com' },
eta: {
filters: {
// 'October 16, 2026', the same on every machine
formatDate: (value: unknown, locale = 'en-US') =>
new Intl.DateTimeFormat(locale, { dateStyle: 'long', timeZone: 'UTC' }).format(new Date(String(value))),
// '4 min read', from the rendered HTML
readingTime: (html: unknown) => {
const words = String(html).replace(/<[^>]+>/g, ' ').split(/\s+/).filter(Boolean).length;
return `${Math.max(1, Math.round(words / 220))} min read`;
},
},
},
});
<% if (stati.page.publishedAt) { %>
<time datetime="<%= stati.page.publishedAt %>"><%= stati.formatDate(stati.page.publishedAt) %></time>
<% } %>
<span><%= stati.readingTime(stati.content) %></span>
- A filter is a plain function on
stati, called like any other. There are no pipes. - The type of a filter is
(x: unknown) => unknown, so in a TypeScript config the first parameter isunknownand the rest are optional.(value: string) => …doesn't compile. - Give dates a
timeZone. Without one, a post published late in the evening lands on a different day depending on where the site is built. - Return HTML only from filters you print with
<%~, because<%=escapes it. - Don't name a filter after something
statialready has, likepageorsite.
In the Stati docs: Custom filters and Template API.