Reflaxe.Elixir supports two valid ways to author Haxe for the BEAM:
- Portable stdlib-first
- Typed Elixir-first
Both are supported today.
Reflaxe.Elixir has one semantics-preserving compilation pipeline (TypedExpr -> ElixirAST -> passes -> printer).
These are authoring styles, not separate backends.
- You do not switch to a separate “portable mode compiler”.
- You do not switch to a separate “metal mode compiler”.
- You choose how much of your app surface is portability-oriented vs BEAM-native extern-oriented.
See also: docs/04-api-reference/FEATURE_FLAGS.md.
Use this when you want maximum cross-target reuse.
Typical characteristics:
- Domain logic uses Haxe stdlib types/APIs.
- Target-specific integrations stay at small boundaries.
- You can often reuse the same domain modules on JS/other targets.
Start here:
docs/02-user-guide/PORTING_STDLIB_CODE_JS_TO_ELIXIR.mddocs/06-guides/PORTABLE_CHAT_TUTORIAL.mddocs/04-api-reference/STANDARD_LIBRARY_HANDLING.md
Use this when your app is primarily Phoenix/Ecto/OTP and you want BEAM-native shapes in your Haxe source.
Typical characteristics:
- Prefer
phoenix.*,ecto.*, andelixir.*extern surfaces. - Decode
Termat boundaries early. - Keep success/error flow explicit with
haxe.functional.Result. - Minimize portability constraints in integration-heavy modules.
Start here:
examples/13-elixir-first-liveview/README.mddocs/02-user-guide/INTEROP_WITH_EXISTING_ELIXIR.mddocs/06-guides/STRICT_MODE.mddocs/06-guides/ADDING_ELIXIR_LIBS_FROM_HAXE.md
Use this in real projects for Gleam-like guardrails in app code. It rejects:
untyped(includinguntyped __elixir__())- explicit
Dynamic - ad-hoc app extern classes (except allowed boundary annotations)
This is a repository policy guard for shipped examples.
It keeps examples Haxe-first by rejecting escape-hatch usage in examples/*/src_haxe/**.
If you are building an app, prefer reflaxe_elixir_strict.
When intentionally writing typed Elixir-first code:
- Prefer Elixir/Phoenix/Ecto extern APIs at integration boundaries.
- Keep
Termboundaries explicit and decode immediately. - Use
Result/Optionfor explicit error/absence handling. - Avoid app-level
untyped __elixir__()andDynamic. - Keep portability-first abstractions for pure domain modules only when they add clear value.
It is reasonable to expect that Elixir-first authoring can reduce some lowering complexity for specific code paths.
Do not claim blanket speedups without measurement.
Use:
haxe build.hxml --times
haxe build.hxml -D macro-times --timesFor repo-level guidance:
docs/06-guides/PERFORMANCE_GUIDE.md
Most production apps benefit from mixing styles by layer:
- Domain core: portable stdlib-first when reuse matters.
- Phoenix/Ecto/OTP edges: typed Elixir-first.
This keeps reuse where it pays off, while keeping framework-heavy code idiomatic and explicit.