Twig adapter
The Twig adapter generates .twig templates for Symfony, Drupal, Craft CMS, and any Twig-capable backend.
Usage
frontmatter solo:build --adapter twig frontmatter solo:build --adapter twig --out ./render-pack
Mapping rules
The Astro-to-Twig conversion follows a small set of consistent rules:
Required props
{# Astro: headline: string #}
{{ fm.props.headline }} Optional props
{# Astro: sub?: string #}
{% if fm.props.sub %}
<p>{{ fm.props.sub }}</p>
{% endif %} Astro slot → Twig block
{# Astro: <slot /> in a layout #}
{% block content %}{% endblock %} Conditional rendering
{# Astro: {condition && <el />} #}
{% if fm.props.condition %}<el />{% endif %} Array iteration
{# Astro: {items.map(item => <Card />)} #}
{% for item in fm.data.items %}
{% include 'partials/card.twig' with { fm: { props: item } } %}
{% endfor %} Page extends layout
{% extends 'layouts/base.twig' %}
{% block content %}
{% include 'partials/hero.twig' with {
fm: { props: fm.data.hero }
} %}
{% endblock %} Output structure
output/ ├─ pages/ │ └─ index.twig ├─ layouts/ │ └─ base.twig ├─ partials/ │ ├─ hero.twig │ └─ section.twig ├─ manifest.json ├─ INTEGRATION.md └─ frontmatter.build.json
Symfony integration
Copy the output to your Symfony templates/ directory. Your controller passes the fm array:
return $this->render('pages/index.twig', [
'fm' => [
'page' => ['title' => 'Home'],
'data' => [
'hero' => [
'headline' => 'Welcome',
'sub' => 'We build things.',
],
],
],
]); Drupal integration
The .twig files work with Drupal's theme layer. Adapt the include paths to Drupal's template naming conventions and map fm.props to Drupal's template variables.
Strict mode
Add --strict to treat framework component warnings (W410–W412) as blocking errors:
frontmatter solo:build --adapter twig --strict