Arizona - a web framework for Erlang/OTP

I have tried with this sys.config and view, and I get this error:

> rebar3 compile
===> Verifying dependencies...
===> Analyzing applications...
===> Compiling qq
===> Compiling src/home_view.erl failed
src/home_view.erl:none: error in parse transform 'arizona_parse_transform':
exception error: Failed to convert Erlang terms to template in home_view at line 20:
error:function_clause:[{arizona_erl,children_ast_to_html,
                           [{bin,
                                {24,29},
                                [{bin_element,
                                     {24,30},
                                     {string,{24,30},"Arizona Hello World"},
                                     default,
                                     [utf8]}]}],
                           [{file,
                                "/home/carloratm/w/qq/_build/default/lib/arizona/src/arizona_erl.erl"},
                            {line,249}]},
                       {arizona_erl,element_ast_to_html,1,
                           [{file,
                                "/home/carloratm/w/qq/_build/default/lib/arizona/src/arizona_erl.erl"},
                            {line,185}]},
                       {arizona_erl,children_ast_to_html,1,
                           [{file,
                                "/home/carloratm/w/qq/_build/default/lib/arizona/src/arizona_erl.erl"},
                            {line,252}]},
                       {arizona_erl,element_ast_to_html,1,
                           [{file,
                                "/home/carloratm/w/qq/_build/default/lib/arizona/src/arizona_erl.erl"},
                            {line,185}]},
                       {arizona_erl,children_ast_to_html,1,
                           [{file,
                                "/home/carloratm/w/qq/_build/default/lib/arizona/src/arizona_erl.erl"},
                            {line,252}]},
                       {arizona_erl,element_ast_to_html,1,
                           [{file,
                                "/home/carloratm/w/qq/_build/default/lib/arizona/src/arizona_erl.erl"},
                            {line,185}]},
                       {arizona_erl,'-ast_to_html/1-lc$^0/1-0-',1,
                           [{file,
                                "/home/carloratm/w/qq/_build/default/lib/arizona/src/arizona_erl.erl"},
                            {line,94}]},
                       {arizona_erl,'-ast_to_html/1-lc$^0/1-0-',1,
                           [{file,
                                "/home/carloratm/w/qq/_build/default/lib/arizona/src/arizona_erl.erl"},
                            {line,94}]}]
  in function  arizona_parse_transform:transform_from_erl/4 (/home/carloratm/w/qq/_build/default/lib/arizona/src/arizona_parse_transform.erl:549)
     *** Arizona Erlang term template parsing failed
  in call from erl_syntax_lib:'-map/2-lc$^1/1-1-'/2 (erl_syntax_lib.erl:86)
  in call from erl_syntax_lib:'-map/2-lc$^0/1-0-'/2 (erl_syntax_lib.erl:86)
  in call from erl_syntax_lib:'-map/2-lc$^0/1-0-'/2 (erl_syntax_lib.erl:87)
  in call from erl_syntax_lib:map/2 (erl_syntax_lib.erl:87)
  in call from erl_syntax_lib:'-map/2-lc$^1/1-1-'/2 (erl_syntax_lib.erl:86)
  in call from erl_syntax_lib:'-map/2-lc$^0/1-0-'/2 (erl_syntax_lib.erl:86)
  in call from erl_syntax_lib:'-map/2-lc$^0/1-0-'/2 (erl_syntax_lib.erl:87)

I’m on erlang 28.1

Ensure you have the most up-to-date Arizona code. Run rebar3 unlock arizona && rebar3 upgrade arizona. I made some fixes hours ago. I’m on my phone, so I’m currently unable to check your issue.

Yeah that was it. Will play with the framework next week.
Expect more feedback.

1 Like

I almost forgot. Thanks for the tip, @hokan! And that’s what I ended up doing:

IMHO, much better! And gives many more possibilities for improvement. Thanks again!

I went through some of the examples provided, it’s very nice indeed!

Some random thoughts, please take those as random thoughts after 1 day of usage:

  1. I tried the rebar plugin to bootstrap a project using the interactive prompt, and if you press a q when asked for the name, it quits. I am not sure that’s a useful tool though, seems very javascript-esque
  2. May be possible to have some kind of facade module to shorten the function calls? Something like az:template_erl instead of arizona_template:from_erl?
  3. Could be possible to load a template from a file instead of a string?
  4. I saw there’s a neovim plugin, does it support vim as well?

Cheers!

1 Like

Thanks!

I need first to sync it with the latest Arizona breaking changes, then I can take a look at the q bug.

Indeed, the plugin needs improvement. Currently, it’s just a template bootstraping, but I have more ideas for it.

Yes! That’s something I want to explore. I need to polish the API first to figure out what the best approach would be.

Yes, but only for HTML and Markdown:

% HTML
arizona_template:from_html({file, "templates/user.html"})
arizona_template:from_html({priv_file, myapp, "templates/user.html"})

% Markdown
arizona_template:from_markdown({file, "content/blog-post.md"})
arizona_template:from_markdown({priv_file, myapp, "content/blog-post.md"})

No, unfortunately. The Neovim plugin is specifically for Neovim’s Lua API.

Thanks again for trying out Arizona! I’ll be waiting for more feedback :smiley:

Looks good, great work!

While trying it out on a Mac it fails with:

✅ Using existing pre-compiled NIF: ../priv/arizona_markdown.so
===> Analyzing applications...
===> Compiling arizona
===> Running cross reference analysis...
=WARNING REPORT==== 10-Feb-2026::21:22:07.297447 ===
The on_load function for module arizona_markdown returned:
{error,{load_failed,"Failed to load NIF library: 'dlopen(/private/tmp/arizona/_build/default/lib/arizona/priv/arizona_markdown.so, 0x0002): tried: '/private/tmp/arizona/_build/default/lib/arizona/priv/arizona_markdown.so' (slice is not valid mach-o file), '/System/Volumes/Preboot/Cryptexes/OS/private/tmp/arizona/_build/default/lib/arizona/priv/arizona_markdown.so' (no such file), '/private/tmp/arizona/_build/default/lib/arizona/priv/arizona_markdown.so' (slice is not valid mach-o file), '/private/tmp/arizona/priv/arizona_markdown.so' (slice is not valid mach-o file), '/System/Volumes/Preboot/Cryptexes/OS/private/tmp/arizona/priv/arizona_markdown.so' (no such file), '/private/tmp/arizona/priv/arizona_markdown.so' (slice is not valid mach-o file)'"}}

===> src/arizona_markdown.erl:98: Warning: arizona_markdown:to_html/1 is unused export (Xref)

this was after rebar3 ci. It tries to use priv/arizona_markdown.so, which is Linux Library.

Not a big deal, maybe delete it from the repository, or is there a more clever way to support multiple architectures? arizona_markdown builds without errors.

1 Like

Thanks for reporting this and for trying it out!

You’re right — the priv/arizona_markdown.so was a pre-compiled Linux ELF binary, so it fails on macOS with a dlopen error.

Rather than patching the build system for cross-platform .so compilation, I replaced the C NIF entirely with WhatsApp’s pure-Erlang erlang-markdown library. It supports the same GFM features (tables, autolinks, strikethrough, task lists, tag filtering) and requires no C compiler at all.

The fix is in #469 — it should work on macOS (and any platform) without issues now.

Just a heads-up: the project is currently in a lazy/unmaintained state as I have very little time to dedicate to it at the moment. Contributions and feedback are still very welcome though!

2 Likes

Hi all, it’s been a while. A lot has changed since the first post.

TL;DR: Arizona 0.1.0 is now on Hex!

This release is smaller than what the project had become. It focuses on the core: pure Erlang templates compiled by a parse transform, and a small, fast diff sent over WebSocket. The old string-based templates are gone. Templates are now plain {Tag, Attrs, Children} tuples. This means tools like LSP, erlfmt, dialyzer, and eqwalizer can read templates like normal Erlang code. The API is also much smaller, and the main code paths (compiling templates, tracking dependencies, diffing) should be faster than before.

What’s in 0.1.0

  • Server-side rendering with live updates: First load is full HTML, later changes are sent as small ops over WebSocket.
  • Pure Erlang templates: {Tag, Attrs, Children} tuples (or {Tag, Attrs} for void elements like <br> or <img>) compiled by a parse transform.
  • Compile-time static/dynamic split: Static parts ship once, only the dynamic parts cross the wire on update.
  • Three handler kinds: arizona_view for route pages, arizona_stateful for components, arizona_stateless for plain template modules.
  • Per-dynamic dependency tracking: ?get(K) marks K as a dependency of its template slot. Only slots whose tracked keys changed get re-evaluated.
  • Streams: Keyed lists with insert, delete, update, move, sort, and reset. Reorders use Longest-Increasing-Subsequence to send the fewest moves possible.
  • PubSub: Cross-view, cross-tab messages via arizona_pubsub (a thin wrapper around pg).
  • SPA navigation: az_navigate links: the server renders the next page over the same WebSocket, no full reload.
  • Route middlewares + on-mount hooks: Block or rewrite requests before mount; run code on every mount, including SPA navigation.
  • Element hooks: Client-side mounted/updated/destroyed callbacks via az_hook.
  • Dev-mode hot reload: A file watcher recompiles changed .erl files and tells the browser to reload.
  • Pluggable transport: Cowboy is the default adapter, but arizona_req is a behaviour you can implement against any HTTP/WS stack.

Many of the old features (markdown, static site generator, and others) are coming back. They will be rebuilt on top of the new pure Erlang base, not restored as they were. More examples and better docs are also planned for the next releases.

Two things are gone for good: Morphdom (the JS client now uses a small op-code patcher with no extra dependencies), and the string-based template format (it was hard for editors and type checkers to read, and most errors only showed up at runtime).

Special thanks to @Taure. He started using Arizona for asobi.dev when the project was almost abandoned. That gave me a real use case and a reason to come back to it.

Feedback, bug reports, and PRs are all very welcome. Happy to answer questions about the parse transform, the diff engine, the dep-tracking model, or anything else.

Give it a try! o/

Cheers!
William

4 Likes