Skip to content
F Flowmark
Framework-agnostic templates

Flowmark

HTML-like templates with modern control flow. Compiled to plain JavaScript.

Get started View on GitHub

Astro-native authoring

@if, @else if, @for, @switch

Inline

template

Rust

compiler

Astro

host

Why Flowmark?

A template language designed for clarity and performance.

@if @for @switch

Modern control flow

Write @if, @else if, @for, @empty, and @switch blocks that read like the host language you already know.

Build-time

Rust compiler

Templates are parsed and compiled to plain JavaScript render functions at build time. No runtime parser, no VDOM.

Astro + Vite

Framework agnostic

Use Flowmark as standalone .flow files with Vite or embed regions directly inside Astro components.

Escaping

Secure by default

Interpolated values are HTML-escaped automatically. Templates are trusted source code, not user input.

Familiar syntax

Control flow that reads like the host language you already know.

Conditional branch
@if (user.isAdmin) {
  <span>Admin</span>
} @else if (user.isMember) {
  <span>Member</span>
} @else {
  <span>Guest</span>
}

Branch on conditions with @if, @else if, and @else.

Iteration loop
@for (product of products; track product.id) {
  <article>
    <h3>{{ product.name }}</h3>
    <p>{{ product.price }}</p>
  </article>
} @empty {
  <p>No products found.</p>
}

Loop over iterables with optional keyed tracking and an @empty fallback.

Switch match
@switch (product.status) {
  @case ('available') {
    <span>In stock</span>
  }
  @case ('sale') {
    <span>On sale</span>
  }
  @default {
    <span>Out of stock</span>
  }
}

Match expressions against multiple cases with a fallback @default.

How it works

From template source to server-rendered HTML.

  1. 1. Author

    Write a Flowmark region inside .astro or a standalone .flow file.

  2. 2. Compile

    The Rust compiler parses the template and emits a plain JS render function.

  3. 3. Inject

    The Astro or Vite plugin replaces the region with the generated render call.

  4. 4. Render

    Astro evaluates the function at build time and emits static HTML.

Real-world example

A changelog list rendered with Flowmark control flow inside an Astro component.

  1. Feature Breaking

    Structured HTML and serializable diagnostics

    v0.2.0

    The parser now understands tags and attributes, and diagnostics carry precise spans and stable error codes.

    Released 2026-06-24

  2. Fix

    Shared JavaScript expression scanner

    v0.1.3

    Interpolation, parenthesized expressions, and for-headers now share one scanner for strings, comments, regex, and template literals.

    Released 2026-06-20

  3. Feature

    Astro integration and inline authoring

    v0.1.0

    Embed Flowmark regions directly inside .astro files with <template flowmark is:raw>.

    Released 2026-06-15

  4. Docs

    Documentation and security policy

    v0.0.5

    Added the specification, security model, and contribution guidelines.

    Released 2026-06-10

Get started

Add Flowmark to an Astro project and embed your first template region.

1

Install

Add the Astro integration and runtime to your project.

Install bash
npm install @flowmark/astro @flowmark/runtime
2

Configure

Register the integration in your astro.config.mjs file.

Configure astro
import flowmark from "@flowmark/astro";

export default defineConfig({
  integrations: [flowmark()],
});
3

Write

Add a Flowmark region to any .astro component.

Write astro
<!-- prettier-ignore -->
<template flowmark is:raw context={context}>
  @for (item of context.items; track item.id) {
    <p>{{ item.name }}</p>
  }
</template>