From 34% to 96%: The Porting Initiative Delivers - Hologram v0.7.0

6 min read Original article ↗

Hologram v0.7.0 is a milestone release for the Elixir-to-JavaScript porting initiative. With 150 newly ported Erlang functions, Erlang runtime coverage has jumped from 34% to 96% - and overall Elixir standard library readiness has grown from 74% to 87%.

This release includes over 700 commits and represents nearly 3 months of focused work on expanding browser-side Elixir capabilities.

The Porting Initiative in Numbers

When we launched the porting initiative in November 2025, 92 Erlang functions had been ported to JavaScript - about 34% of what's needed for Phase 1. Since then, we've ported 150 more functions across 19 modules, pushing Erlang coverage to 96% (228 out of 238 Phase 1 functions done, 10 in progress, 0 remaining in the backlog). Elixir standard library readiness has grown from 74% to 87% (this metric reflects the average progress of Elixir stdlib functions based on how many of their underlying Erlang dependencies have been ported).

This means the vast majority of Elixir standard library functions needed for Phase 1 (full-stack web and basic local-first apps) now work in the browser. Functions for string manipulation, collections, math, sets, binary operations, Unicode normalization, file path handling, time operations, and more - all available client-side. Process-related modules remain deferred to Phase 2. Note that some functions in the client runtime reference may appear below 100% - this is because the compiler conservatively marks certain functions for client-side inclusion, but in practice they won't be needed for web applications. This will be addressed in following releases.

A huge thanks to all 49 contributors who took part in the porting initiative. Special shout-out to @mward-sudo (Michael Ward), who single-handedly ported several modules with complex code. Also thanks to @tenkiller (Brett Fincher), @Sorc96, @Lucassifoni (Lucas Sifoni), @ideaMarcos (Marcos), and @Petarj123 (Petar Jankovic), each of whom contributed multiple ports - and to everyone else who contributed to the porting effort 💜

Here's the breakdown of newly ported functions by module:

Erlang module Functions ported
:binary 13
:elixir_aliases 1
:elixir_locals 1
:elixir_utils 1
:erlang 57
:filelib 1
:filename 10
:init 1
:lists 19
:maps 7
:math 5
:os 3
:rand 1
:re 1
:sets 13
:string 9
:unicode 5
:unicode_util 1
:uri_string 1
Total 150

What This Unlocks

With these ports in place, many more Elixir standard library functions now work in the browser. Here are some examples of what you can use client-side:

  • String processing - String.split/3, String.replace/4, String.length/1, String.jaro_distance/2, and titlecase operations all work in the browser now
  • Collections - Enum and List functions backed by :lists (sorting, filtering, folding, key-based operations on keyword lists) are now available
  • Sets - Full MapSet support via ported :sets functions - create, filter, intersect, union, and check membership
  • Binary & bitstring operations - Pattern matching, splitting, replacing, and searching within binaries
  • Unicode - NFC, NFD, NFKC, and NFKD normalization, plus grapheme cluster segmentation
  • Math - Float.ceil/1, Float.floor/1, power, logarithm, and exponent functions
  • Time - Monotonic time, system time, time unit conversion, and time offsets
  • File paths - Path.join/2, Path.basename/1, Path.dirname/1, Path.extname/1, and more (for client-side path manipulation, not filesystem access)
  • And many, many more - check the Client Runtime Reference for the full picture

Enhancements

Beyond porting, this release brings several improvements that directly affect how you build with Hologram:

  • Faster compilation (#281, thanks @mwmiller) - Compiler mutations are now asynchronous via Agent.cast/2, resulting in measurable compile speed improvement
  • Cross-platform mix setup - Added a setup task for Hologram contributors that works on macOS, Linux, and Windows
  • NixOS compatibility (#639, thanks @ankhers) - Automatic fallback to system-installed Biome when the dynamically-linked Biome dependency binary can't run (common on NixOS, Alpine, and similar systems)
  • More :erlang.float_to_binary/2 options (#371, thanks @ideaMarcos) - :decimals, :compact, and :scientific formatting options are now supported alongside :short
  • Raw HTML blocks in Parser (#287, thanks @mwmiller) - :raw blocks are now emitted from the Parser, enabling more accurate source reconstruction

Bug Fixes

Some of these fixes were already shipped in v0.6.x patch releases:

  • Quota exceeded during page navigation (#272) - Fixed DOMException: The quota has been exceeded by implementing hybrid storage strategy with OPFS
  • Map immutability (#521, thanks @Lucassifoni) - :maps.remove/2 and :maps.put/3 no longer mutate the original map, preserving Erlang's immutability semantics
  • Template interpolation (#276) - Templates now use the String.Chars protocol for interpolation, matching how Elixir string interpolation works, on both client and server
  • Pattern matching with placeholder on right (#642, thanks @prehnRA) - Patterns like :top = _position now work correctly in transpiled code
  • Form events (#260) - Fixed form-level change event detection and submit event form data collection
  • URL parameter encoding - page_path/2 now properly encodes URL parameters, and query params are correctly decoded on navigation, including special character sequences like . and .. that could otherwise trigger path resolution
  • Bitstring segment handling - Fixed placeholder matching and unit resolution in bitstring patterns
  • AST normalization - Fixed handling of try/rescue/catch function ASTs
  • :unicode_util.cp/1 error behavior (#636, thanks @mward-sudo) - Error messages now correctly reference the internal :unicode_util.cpl/2 function, matching Erlang's actual behavior
  • Unported function error message (#640, thanks @prehnRA) - Improved the error message shown when an unported function is encountered; the previous message pointed to a non-existent URL

Infrastructure

Under the hood, this release lays groundwork for upcoming features:

  • Client-side ERTS - New runtime system class with node table, sequence generators, binary pattern registry, and UTF-8 decoder
  • Reference type overhaul - Redesigned internal format and serialization of reference terms to better mirror Erlang behavior
  • ETS infrastructure (#504) - Foundational support for ETS, including state preservation when navigating away from the app
  • Page snapshot improvements - Three-tier storage strategy: in-memory caching for fast access, async OPFS (Origin Private File System) persistence, and session storage as fallback

Upgrading

Update the Hologram dependency in your mix.exs:

{:hologram, "~> 0.7.0"}

Then run:

$ mix deps.update hologram

Thank You

This release would not have been possible without our sponsors and the contributors who joined the porting initiative.

Sponsors

I'd like to thank our sponsors whose support makes sustained development possible:

  • Main Sponsor: Curiosum - ongoing sponsorship along with business insight and adoption guidance, helping shape Hologram's roadmap based on real-world production needs
  • Milestones Sponsor: Erlang Ecosystem Foundation - milestone-based stipend, helping fund key development goals

Thanks also to our GitHub sponsors:

And to all other GitHub sponsors - thank you. Every contribution, no matter the size, helps keep Hologram moving forward.

If you'd like to support Hologram's development, consider sponsoring the project.

Stay in the Loop

Subscribe to the Hologram newsletter for monthly updates on new releases, features, and community news.

What's Next

With 96% of Erlang functions needed for client-side web apps already ported, we're steps away from having a reliable and comprehensive Elixir runtime in the browser. Going forward, expect more granular and more frequent minor releases as we finish the last few pieces of the puzzle and shift focus to polish and stability.

- Bart

Sponsored by

Curiosum Erlang Ecosystem Foundation