# Run \*\*native\*\* Elm on your server and your terminal! Yes, native!

**URL:** <https://discourse.elm-lang.org/t/run-native-elm-on-your-server-and-your-terminal-yes-native/10747>\
**Category:** Show and Tell\
**Created:** [June 2, 2026, 2:03pm UTC](https://discourse.elm-lang.org/t/run-native-elm-on-your-server-and-your-terminal-yes-native/10747 "2026-06-02T14:03:52Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![damir](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/damir/32/5549_2.png) [@damir](https://discourse.elm-lang.org/u/damir)\
**Post date:** [June 2, 2026, 2:03pm UTC](https://discourse.elm-lang.org/t/run-native-elm-on-your-server-and-your-terminal-yes-native/10747/1 "2026-06-02T14:03:53Z")

</div>

```elm
module Hello exposing (main)

main : String
main =
    "👋"

```

```auto
$ run make -o hello CLI/Hello.elm

$ ./hello
"👋"

```

“👋” friends!

It’s finally here: a true native Elm experience we’ve all wished for! **elm-run** will run your Elm on the server and on your CLI, in your TUI programs and in your games, unspoiled! No more of that ugly JavaScript duck tape we had to do so far.

After exactly six months of nonstop development, behold the first beta version!

## What is it exactly?

It’s a runtime the same way Node.js is for JavaScript code: you compile your Elm to assembly code and it either executes it directly or produces true native OS binaries, like a C compiler would. Runs on macOS, Linux, and Windows.

```
┌───────────┐                                                                                    
│ │─┐                                                                                  
│elm source │ │┐ ┌─────────────┐ ┌─────────────┐ ┌────────────┐ ┌────────────┐
│ │ ││ │ │ │ │ │ │ │ │
└───────────┘ │├─────►│elm compiler ├────►│ elm ir ├──────►│ js codegen ├────►│ browser │
 └────────────┘│ │ │ │ │ │ │ │ │
   └───────────┘ └─────────────┘ └──────┬──────┘ └────────────┘ └────────────┘
                                                 │                                               
                                                 ▼                                               
                                           ┌─────────────┐ ┌────────────┐ ┌────────────┐
                                           │ │ │ │ │ │
                                           │run optimizer├──────►│ codegen ├────►│ runtime/OS │
                                           │ │ │ │ │ │
                                           └─────────────┘ └────────────┘ └────────────┘

```

In short, you use the exact same Elm you know and love, and **elm-run** runs it for you on your computer + server, fast, right on the OS, just like `cat` or `grep` or other utilities. It runs all existing published packages. (Okay, maybe not those made for the browser).

But it also runs Elm in a fast, native 3D game engine: from your Elm program straight to the GPU!  
No weird transpilations, “bindings,” and whatnot! No contorted “diagram languages.” Just Elm the way you already write it.

**elm-run** is not an experiment: it’s a proper product aimed at professionals. And for enthusiasts, with **elm-game**. Everyone benefits, but the features are chosen for pro use, informed by my professional experience (SaaS, e-commerce, e-mail, databases).

## Is it really native?

Yes! The real thing! No piggybacking on Node, no _“… well, actually it’s just lipstick on JavaScript.”_. No transpiling to some other source for yet some other compiler to process, no llvm. (Believe it or not, llvm produces 15% slower VM run loop than the one we ship! Seriously). So, it’s just Elm and your computer.

No, it’s not WebAssembly. **elm-run** does its own VM + codegen + native emission. **elm-run** is written in itself, without dependencies: it compiles Elm intermediate language, optimizes for native, emits assembly code for macOS, Linux, and Windows with Intel and Arm processors. It’s not a “dynamic language.” It’s ahead-of-time compiled and optimized bytecode. It also compiles down to straightline executable machine code!

It’s open source, like Elm, and it’s not some “language inspired by Elm:” it **runs the stock Elm compiler, unchanged** and will never ever attempt to change Elm.

## Why?

I really enjoy writing programs in Elm. It’s a fun and pleasant language. In my business, I have needs beyond the browser, and jumping between the pleasant Elm experience and other languages suitable for backend/db development caused me unpleasant cognitive dissonance for years. And I just can’t swallow all this JS/node business. Never could.

Add to that my growing concern with all these security issues we’re seeing with the supply chain, a chance idea (I needed an interpreter for **elm-wrap** ), and well, here we are: “👋”.

A proper solution deserves dedication and focus, so I decided to invest this year in solving my cognitive dissonance and lay the groundwork for reimagining the way we write, run, and share code. Put my business aside, and dove into this for days and days, without pause.

The outcome is **elm-run** , the runtime. Behold! An unapologetically ambitious product that aims to elevate Elm in your life and your work!

## Use it today

Today I’m inviting you to beta test:

- **elm-run** compiler, the thing that takes Elm compiler’s output and produces the bytecode / native outputs.
- `run` orchestrator tool that lets you manage your native Elm coding experience.

The runtimes (things that execute those compiled programs):

- Command line `host-run` that runs CLI programs and TUI programs;
- `host-worker`, a web server with integrated async/multithreaded Elm runtimes, automatic TLS, etc.;
- and **elm-game** , the 2D/3D game engine. 👈 _My new favorite!_

I’ve been enjoying all these things for a while now: writing code generators for the virtual machine and standard library, CLI utilities, profiler, debugger, etc. It’s fun! It even runs on **elm-wrap cloud** in production! However modest that may be, we can say it’s already a “production runtime,” even though we’ve still got a ways to go before a 1.0 release.

## What do these do?

### Cli + TUI

The CLI runtime is the workhorse, the daily driver.

So far we had to jump through hoops with various JS runtimes, have `Ports` blues, and spend most of our time writing this horrible plumbing instead of being productive with Elm!

**elm-run** changes that forever!

Write your normal headless Elm like you are used to, `run` it and that’s it! It will run both simple and complex workloads, async or multi-threaded (Actors! Yay!), fetch stuff with HTTP, TCP, or sockets. It knows all the advanced things one would expect from a proper “server-grade runtime.” (protip: Nonchalantly throw around terms like _shared memory_ at team meetings).

CLI runtime is powerful and fast. It’s tighly integrated with Elm: it _knows_ Elm in the async reactor core! It’s made for Elm and for TEA and nothing else! No compromise! `run` utility runs on that one, so does the compiler. It also works as a proper OS process on the server, like your job workers. In fact, it’s great on the server! With the bytecode distribution model, it’s way safer than shipping just some random llvm-produced executables. It has all the goodies that a pro ops team  
would expect: SFI, auditing, capabilities, …

Programming is exactly how you’d imagine. It has the run loop and init-\>update-\>subscriptions cycle. It can do one-shot batch mode or run infinitely as an OS process.

Here’s the `grep` example from _The Book of **elm-run** _ (that you’ll get in the beta toolkit):

 ![Familiar, eh?](https://canada1.discourse-cdn.com/flex035/uploads/elm_lang/original/2X/4/404ea5d81638c7e89924b5b144ca119be529ad1f.jpeg)

It also knows how to render TUIs for you. Natively integrated into your OS, with a fast view engine. Just like all those other TUI toolkits. Except this one feels like home:

```elm

import Terminal.Tui.View as V

...

bg : ( Int, Int, Int ) -> V.Attribute msg
bg ( r, g, b ) =
    V.bgRgb r g b

view : Model -> View Msg
view model =
    let
        cols =
            max 1 model.windowSize.cols

        rows =
            max 1 model.windowSize.rows

        bodyRows =
            max 1 (rows - 2)
    in
    V.column
        [ V.widthCells cols
        , V.heightCells rows
        , bg Theme.bg
        , fg Theme.text
        ]
        [ topBar cols model
        , dashboard cols bodyRows model
        , footerStatus cols model
        ]

main : Terminal.Program Model Msg
main =
    Terminal.program
        { init = init
        , view = view
        , update = update
        , subscriptions = subscriptions
        }

```

I find it practical to have a small TUI app around to monitor the production db of my wife’s online shop. But I also use little TUI programs for overseeing tests, matrix tests, and a bunch of other things like analyzing code the compiler produced.

 ![mysqlmon](https://canada1.discourse-cdn.com/flex035/uploads/elm_lang/original/2X/3/3c55a8310d4f2ba9439787db9395c526dc374534.jpeg)

### Actors

All hosts run a fully async reactor loop (written in C targetting native async idioms of each OS). Parallelism is through `Actors` that are nothing more than “mini-TEA” programs themselves:

```elm
Actor.spawn
    (Actor.program
        { init = workerInit
        , update = workerUpdate
        , subscriptions = workerSubscriptions
        }
        { replyTo = mainPid }
    )

```

Simple and fun! Familiar and powerful! Super useful for non-blocking UIs in TUI and **elm-game**.

There are also simpler “Type A” actors that are just `Task`s executed on their own thread.

### Web server

A web server that serves async web requests exactly how you’d imagine: subscribe to a request and process it async! Or maybe you want to process a web socket or a TCP connection. Familiar and boring in a good way!

This is my test corpus fixture, httpbin style:

```elm
main : Worker.Program Model Msg
main =
    Worker.program
        { init = init
        , update = update
        , subscriptions = subscriptions
        }

subscriptions : Model -> Sub Msg
subscriptions model =
    Http.onRequest GotRequest

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        GotRequest req ->
            if req.path == "/quit" then
                ( model, Worker.exit 0 )

            else if req.path == "/echo" then
                -- Echo the request body verbatim. Used by HttpPostBodyTest /
                -- HttpPutBodyTest to verify the client forwarded the body.
                ( model
                , Http.respond
                    { connectionId = req.connectionId
                    , streamId = req.streamId
                    , status = 200
                    , contentType = "text/plain"
                    , body = req.method ++ " " ++ String.fromInt (String.length req.body) ++ " " ++ req.body
                    }
                )
            ...

```

It runs the same VM as the other hosts, so it can do all the same things like spawn actors, OS processes, etc. It also happens to be the industrial-strength, hyperscaler-grade web server.

### The Game

And then there’s **elm-game** , my new favorite! Hadn’t looked at it for months, thinking I’ll release by 0.6.0 per the [roadmap](https://elm-run.dev/roadmap). But then @MartinS asked if it can mix audio in pure Elm and _stream_ it. Hmm…

[![](https://img.youtube.com/vi/cjbZSqWpvic/maxresdefault.jpg "audiomix") ](https://www.youtube.com/watch?v=cjbZSqWpvic)

So yes, pure audio mixing in Elm and just stream it to the OS: `Sound.queuePcm { sampleRate = outputSampleRate, channels = 2, samples = samples } `. Look ma! No ports!

Haven’t done anything but since Friday, almost missed the release deadline today! Disaster! But haven’t had this much fun in a while!

Always been a fan of Lua LÖve, even tried making a few small games with my son way back when. I’d patiently explain to him, “Son, every engine always has an init phase, the run loop, and the frame renderer. And it processes your stick and keyboard inputs when they come. Nothing much to it: init, update, view, pick up input events.”

Time passed, he studies Game Design. Early on into **elm-run** , he’s working next to me in the office, struggling with his assignment in Unreal. That beast might be the “cutting edge”, “pro” thing, but wow does it kill any joy! You have an idea for a quickie little mechanic to try out, but that beast just hammers you in with all the endless menus and weird UI stuff and its C++ that isn’t! You’re like, never mind.

Hmm, 🤔… init, view, update, subscribe… native Elm on my screen…

It’s a time stealing monster friends! It’s so addictive, I’m afraid to release it before we test the “pro” runtimes! I’m afraid you’ll ignore the cool web server and the CLI! (I keep convincing myself, “it’s good for perf testing.”)

 ![Elman](https://canada1.discourse-cdn.com/flex035/uploads/elm_lang/original/2X/e/ef100286940b5382484caf11968686fb299d2539.png)

It’s a decent little engine, in the spirit of Elm. Does all the usual 2D and 3D stuff; and audio without Ports! Obviously, multithreaded through Actors. And it’s just Elm, packages and all. Not being much of a game maker, I’m hoping all you good people will make it great! And make great games! **Elm game** jams! Yay!!!

[![](https://img.youtube.com/vi/4Fz8zUMyOfo/maxresdefault.jpg "elm game gears") ](https://www.youtube.com/watch?v=4Fz8zUMyOfo)

It’s a really funny feeling to write Markdown in immediate mode in Elm, just blitting pixels to the screen (and the GPU) and laying things out. Didn’t expect it to feel so liberating without `Html` and virtual dom!

 ![book](https://canada1.discourse-cdn.com/flex035/uploads/elm_lang/original/2X/0/0eedae5a0ebddd9f2b5b36ea7c580471c3c19802.jpeg)

## Welcome to Native!

So friends, we start today! This early beta is by invitation. Not because I don’t love you (I do, 🫶). It’s just that I have limited mental bandwidth, and have been writing this code for so long that I simply don’t hit the bad corners anymore. Yet almost everyone that tried it ran into a new problem I haven’t seen before within hours: either under-optimized parts or mysterious compile errors due to code shapes I never thought of trying, or stacks of packages I didn’t know existed!

_Native_ here truly means that: three platforms, two architectures. All the stuff that V8 and the browser do for Elm in the Browser, **elm-run** has to do by itself. And there’s a LOT of it! No single human can hope to test that and find all the rough spots.

So, if you don’t mind, I’d like you to tell me you’re interested at [the beta page](https://elm-run.dev/beta) by sending some info about your hardware, and then I’ll start contacting you, subject to how quickly I can turn around any issues we find, and your declared tolerance for things that break.

The goal is to onboard everyone rapido! I’d love to start with a good mix of macOS/Linux/Windows early adopters, and then expand in order of improvements and my ability to support everyone.

I’m more of a relationship person, preferring to work one-on-one with interested people. If you’re trying it, means you invested your time into something I did, so at least I can pay you back with attention and support.

The smoother things get, the more people I can onboard. I gather a month, maybe two, should do until we start seeing really stable products. And hopefully some games!

This is the first time for me to release such a massive and ambitious developer product. I know for a fact that for most of you it is a waste of time have to try something only for it not to meet your expectations, and then you have to wait for things to improve. Kills the fun. I’d rather you have a great start. Some people, on the other hand, are tolerant to these things. So I’m hoping we have a good mix here!

I’m very much looking forward to Elm Camp to have productive and informed discussions and talk ideas! I’m DYING to see the stuff you’ll do.

## The Conversation

I’ll provide communication details in the invitation (issue reporting, binary updates, etc). **elm-talk** will likely be the only channel for bug reporting and technical discussions. It’s almost ready to go live! Just a bit more backend work.

 ![elm-talk](https://canada1.discourse-cdn.com/flex035/uploads/elm_lang/original/2X/b/bf68ebae5fe6427271b0619938dd4a15fd82e40e.jpeg)

In the meantime, please ask questions here in public, or contact me through this discourse, on Slack, Discord, phone, whatever works for you! My door is always open and I’m excited to talk!

I’ll post occasional updates here and on the site as well.

## Mandatory Answers

- Is this open source?  
Yes, bona-fide, BSD licensed open source. Just like Elm itself.  
Even comes with a book of internals, so you can learn stuff if you’re into low level things. But the source for the runtime and compiler is not yet public. It will be, but only after 1.0.

- What’s it made in? Did you use _hip language/tool X_?  
No.  
I started on December 1 '25 by writing a small C interpreter for Elm IR, slowly getting it just fast enough to run larger Elm programs, and then moved as much as I could to Elm.  
A career in tech taught me that the best and most sustainable products come from making your own cake all the way. No transpiling to _X_, no llvm backend, no _some thing random people on the internet tell you is magically fast because is written in some equally magical language that some other random people say that is fast because, well, some rando in some big brand company tried it once and tweeted about it_.  
Friend, this cake has only three ingredients: Elm, assembly (written in Elm), C. More and more Elm/assembly, less and less C.

- Yes. It builds on Linux, macOS and Windows.  
macOS is my platform so that’s the most tested. I wrote most things cross-platform and am now building on all platforms daily. And Elm bytecode tools obviously run cross-platform. One nice benefit of choosing that architecture. Saves a lot of build minutes!

- Is it fast? Yes, decent. But let’s revisit this question after v0.5.0.  
The VM already executes around the same speed as WASM3 interpreter on a few synthetic WASM tests I could find. That target worked as predicted! Not very meaningful for judging the speed of your programs, but at least the base is ok. **The Book** guides you in writing a small CLI program that goes faster than system utilities like `grep`.  
There’s also a very very fast compiler to native executables that runs more and more programs on the test corpus. I don’t know the final speed yet, but writing all that assembly is paying off! Let’s wait for 0.5.0.

- Wut? A “VM”?! That’s slow! Cool kids use llvm!  
A purpose-built runtime with tight loops and ops in handwritten assembly is the right choice for all the productive scenarios Elm is suitable for. You can’t do secure distribution with native binaries without cooperation of OS gatekeepers. Ask any pro ops person: small, audited runtime with SFI and capabilities + inspectable deliverables; or an opaque executable compiled with some rando’s llm’d llvm that won’t be buildable with the next version of llvm?  
**elm-run** aims at pro use. It’s fast enough. And as mentioned, llvm/mlir/whatevaIR are not made for functional languages. No matter what they sell you. A runtime and compiler that know the language intimately, made for that language–in that language–are an infinitely larger long-term win over chasing “native compilation” by depending on some third party’s vision of what that means.  
If I may say so myself, **elm-run** is an elegant and enjoyable product–second only to Elm itself!-- so you won’t mind waiting a few more months for insta-compiled native. (And you won’t have to recompile whatever you already shipped).

- Can I run it in production?!  
I do! It’s still beta, though, and it is beta exactly so you run it in prod and help discover any warts! But I don’t know what you do. Let’s talk.

- Is this it?  
No. This is just table stakes to do all the exciting stuff. I’m looking forward to your help; the minute this product is out, I have an insane pipeline of stuff to release. Elm is truly a _productivity language_! And now unchained from the browser,… wow!

Once you pick this up, I hope you’ll be as excited as I am!

* * *

~~In a most embarrassing turn of fate, I misconfigured a backend and the beta page can’t submit applications! Super embarrassing! Blame **elm-game**! Will provision a new server soon with a clean setup, but safer to say that the page goes up tomorrow. Contact me directly in the meantime! Don’t hesitate.~~

The form now works if that’s your preferred way. Thank you all for great interest! 🫶

---

<div class="post-metadata">

**Author:** ![jfmengels](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/jfmengels/32/3124_2.png) [@jfmengels](https://discourse.elm-lang.org/u/jfmengels)\
**Post date:** [June 2, 2026, 2:46pm UTC](https://discourse.elm-lang.org/t/run-native-elm-on-your-server-and-your-terminal-yes-native/10747/2 "2026-06-02T14:46:10Z")

</div>

Hey folks 👋

I’m adding to the announcement that I have been working with Damir on rewriting `elm-review` with `elm-run`. The intent is to have `elm-review` rewritten fully in Elm, and hopefully to crank out better performance. Also, going to native would allow running the tool without Node.js and `npm`, allowing it to be installed in a standalone way or with `elm-tooling`, and distances us from the daily security problems in the `npm` ecosystem.

I’m one of the few who’s hit the bad corners (over and over again) so I have been giving Damir a lot of extra work 😁  
I’m not yet at the point where I can tell you whether it’s faster with `elm-run` or with Node.js, but I hope to give more updates soon!

However, the rewrite to Elm has been very pleasurable. It’s simply the language and experience that I have come to love over these years, mostly with more access to `Tasks` 😁

Going from `Node.js` to 100% Elm for all the CLI work has been a lot of rewrite work (because it accumulated a lot of features over the years) but really fun.

And the result is so much nicer than before. Being able to rely on `Task`s instead of JS ports reduces the amount of state one needs to manage a lot. The whole architecture feels a lot nicer, it feels a lot more maintainable, and I’ve uncovered a number of edge cases and problems that weren’t handled properly in JS but that the Elm compiler caught and asks me to handle.  
(Un?)Surprisingly, none of that was caught when I was adding TypeScript to the codebase… 😞

I’ve definitely enjoyed working with `elm-run` so far 😊

---

<div class="post-metadata">

**Author:** ![rupert](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rupert/32/1775_2.png) [@rupert](https://discourse.elm-lang.org/u/rupert)\
**Post date:** [June 2, 2026, 2:51pm UTC](https://discourse.elm-lang.org/t/run-native-elm-on-your-server-and-your-terminal-yes-native/10747/3 "2026-06-02T14:51:03Z")

</div>

> [@jfmengels](#):
>
> However, the rewrite to Elm has been very pleasurable. It’s simply the language and experience that I have come to love over these years, mostly with more access to `Tasks` 😁

Curious about this comment - are you writing custom Tasks for elm-review ? Or do you just mean that you have more IO Tasks available from the elm-run platform ?

---

<div class="post-metadata">

**Author:** ![jfmengels](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/jfmengels/32/3124_2.png) [@jfmengels](https://discourse.elm-lang.org/u/jfmengels)\
**Post date:** [June 2, 2026, 2:56pm UTC](https://discourse.elm-lang.org/t/run-native-elm-on-your-server-and-your-terminal-yes-native/10747/4 "2026-06-02T14:56:11Z")

</div>

I have access to more IO Tasks from the `elm-run` platform, specifically around access to the file system or spawning commands which are not there in plain Elm, and that I had to previously use ports for.

---

<div class="post-metadata">

**Author:** ![supermario](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/supermario/32/92_2.png) [@supermario](https://discourse.elm-lang.org/u/supermario)\
**Post date:** [June 2, 2026, 4:05pm UTC](https://discourse.elm-lang.org/t/run-native-elm-on-your-server-and-your-terminal-yes-native/10747/5 "2026-06-02T16:05:25Z")

</div>

Very excited to play around with this! Congrats on the initial release 🎉

---

<div class="post-metadata">

**Author:** ![dirkbj](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/dirkbj/32/3162_2.png) [@dirkbj](https://discourse.elm-lang.org/u/dirkbj)\
**Post date:** [June 2, 2026, 6:07pm UTC](https://discourse.elm-lang.org/t/run-native-elm-on-your-server-and-your-terminal-yes-native/10747/6 "2026-06-02T18:07:37Z")

</div>

🤯 😃 🤯

My mind is running through so many things this empowers.

🤔 🤯 🤔

Excited to build on this. Amazing. Thank you. 🙏

---

<div class="post-metadata">

**Author:** ![damir](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/damir/32/5549_2.png) [@damir](https://discourse.elm-lang.org/u/damir)\
**Post date:** [June 3, 2026, 12:33pm UTC](https://discourse.elm-lang.org/t/run-native-elm-on-your-server-and-your-terminal-yes-native/10747/7 "2026-06-03T12:33:08Z")

</div>

Friends! The beta form is live if you prefer it over contacting me directly. Ping me through the [form](https://elm-run.dev/beta) or here or on Slack. People are contacting me in all these ways, so whatever works best for you.

Regret again the delay!

---

<div class="post-metadata">

**Author:** ![benjamin-thomas](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/benjamin-thomas/32/3869_2.png) [@benjamin-thomas](https://discourse.elm-lang.org/u/benjamin-thomas)\
**Post date:** [June 3, 2026, 12:36pm UTC](https://discourse.elm-lang.org/t/run-native-elm-on-your-server-and-your-terminal-yes-native/10747/8 "2026-06-03T12:36:07Z")

</div>

Man, this looks so cool, can’t wait to try it!

Is there a place where we’ll be able to follow development and discussions as they happen?

As a user, I’d like to be able to, eventually, understand my programs from the high level Elm representation, to the lower level stuff. Obviously this takes a while to master, but having a book of internals sounds very compelling to me, to avoid having a “black box” feeling.

One thing that pops to mind is OCaml having a “rewind” step debugger (works only on byte code output though). I believe some variations of this idea exist even with certain C debuggers, but limited due to unrestricted IO. I don’t know what you have in mind there, but it sounds like this could be quite the differentiating factor (time travel possible maybe?).

Happy to see where this goes, and I hope you can find a way to monetize so that you can keep working on this comfortably.

---

<div class="post-metadata">

**Author:** ![kantuni](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/kantuni/32/5397_2.png) [@kantuni](https://discourse.elm-lang.org/u/kantuni)\
**Post date:** [June 3, 2026, 6:40pm UTC](https://discourse.elm-lang.org/t/run-native-elm-on-your-server-and-your-terminal-yes-native/10747/9 "2026-06-03T18:40:39Z")

</div>

This sounds amazing! We at [Feedback.one](https://feedback.one) would looove to try it out!

---

<div class="post-metadata">

**Author:** ![Confidenceman02](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/confidenceman02/32/4396_2.png) [@Confidenceman02](https://discourse.elm-lang.org/u/Confidenceman02)\
**Post date:** [June 4, 2026, 12:51am UTC](https://discourse.elm-lang.org/t/run-native-elm-on-your-server-and-your-terminal-yes-native/10747/10 "2026-06-04T00:51:36Z")

</div>

There is about a billion things I could use this for in [djelm](https://github.com/Confidenceman02/django-elm) for running elm on a django server. Damn fine work my man!

---

<div class="post-metadata">

**Author:** ![agj](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/agj/32/3966_2.png) [@agj](https://discourse.elm-lang.org/u/agj)\
**Post date:** [June 4, 2026, 4:36pm UTC](https://discourse.elm-lang.org/t/run-native-elm-on-your-server-and-your-terminal-yes-native/10747/11 "2026-06-04T16:36:33Z")

</div>

This sounds very interesting indeed, thank you for the work. However, I do have to ask. @damir, is this project vibe-coded?

---

<div class="post-metadata">

**Author:** ![damir](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/damir/32/5549_2.png) [@damir](https://discourse.elm-lang.org/u/damir)\
**Post date:** [June 4, 2026, 8:39pm UTC](https://discourse.elm-lang.org/t/run-native-elm-on-your-server-and-your-terminal-yes-native/10747/12 "2026-06-04T20:39:37Z")

</div>

Wish I had some time to vibe in these past months!

No. This is not vibe coded, in any sense of that phrase.

This is an original, premeditated product, with clear positioning, clear objectives, tech choices and the roadmap I obsessed over for weeks before I committed to it, and then published. There are witnesses here that can confirm that part for you.

In short, the exact opposite of these vibe-coded things we’re seeing: high-on-slop-fumes overhyped desperate-attention-seeking vague claims of “innovative, novel, unique;” lack of clear direction; no premeditated objectives and positioning; no coherent tech strategy in line with stated objectives. Impenetrable mountains of slop in languages and tools decided by the machines.

FWIW, at this scale of code and effort, I don’t think these tools can deliver the goods without product discipline.

Conversely, at this scale of code, effort, and investment, I believe it would be irresponsible not to use all the tools we have at our disposal.

Since you had to ask, I was obliged to answer.

Now I have to ask: could we please not continue this line of conversation, and keep the questions (and praise!) about elm-run?

---

<div class="post-metadata">

**Author:** ![Stephan\_Muller](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/stephan_muller/32/4754_2.png) [@Stephan\_Muller](https://discourse.elm-lang.org/u/Stephan_Muller)\
**Post date:** [June 6, 2026, 7:57am UTC](https://discourse.elm-lang.org/t/run-native-elm-on-your-server-and-your-terminal-yes-native/10747/13 "2026-06-06T07:57:54Z")

</div>

I can’t even imagine the amount of effort and skill that went into this. Crazy work, thank you!

---

<div class="post-metadata">

**Author:** ![john\_s](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/john_s/32/4425_2.png) [@john\_s](https://discourse.elm-lang.org/u/john_s)\
**Post date:** [June 9, 2026, 4:30pm UTC](https://discourse.elm-lang.org/t/run-native-elm-on-your-server-and-your-terminal-yes-native/10747/14 "2026-06-09T16:30:06Z")

</div>

Amazing!!! Inspiring! Impressive! Thank you for this work.

## Elm Community

What impact does this have on the Elm community in terms of packages and training materials? I **love** the idea of being able to do so much more without actually changing the language and I appreciate

> [@damir](#):
>
> It’s open source, like Elm, and it’s not some “language inspired by Elm:” it **runs the stock Elm compiler, unchanged** and will never ever attempt to change Elm.

How does this work in practice? If there are packages that are only available on this platform then doesn’t that fragment Elm a little and so change Elm? Obviously this all hinges on what you consider to be “Elm”: a language with a type system and compiler, a philosophy, a package ecosystem, a community, etc.. Right now Elm refers to all of that.

Do you see elm-run impacting that unity in any way? If so what are your thoughts?

## Package Discovery

How will we organize and discover packages that work in the browser, as a CLI, as a native server, as a game? Do you envision organizing these things by platform or by granular capabilities or…?

I just ran over and spent 5 minutes looking at some [Gren Packages](https://packages.gren-lang.org/) and their search interface.

- It looks like their libraries declare a platform of “node” | “browser” | “common”. The [gren-tui](https://github.com/blaix/gren-tui/blob/5.0.0/gren.json) package configuration has “node”, the [gren-hex](https://github.com/aramiscd/gren-hex/blob/1.0.3/gren.json) has “common”, and the [browser](https://github.com/gren-lang/browser/blob/6.0.2/gren.json) module obviously has browser.
- However, when I look around Gren’s package search interface I see a fairly significant gap: I cannot tell which platform a package supports from the search page. Maybe someone familiar with Gren can explain it better or maybe I am just missing something obvious. I would find it really valuable to be able to quickly and immediately discover things that can work in different contexts.

## NodeJS?

It looks like we get a native server option that can receive Http requests and respond without ports. Great!!!

What about those wishing to run their server on NodeJS in order to use existing NodeJS libraries? Or perhaps they prefer NodeJS as a platform for other reasons? Is it simply the case that you would only use elm-run if you wanted a native server? That sounds like a good and distinct product position and I am probably speaking to an edge case, but it seems that offering a NodeJS solution that removed the need for ports for Http handling could be useful; benefiting from normalized Apis around Http request handling. Or maybe not worth the complexity. 🤷‍♂️

## Super Awesome

The above is intended only as light inquiry. To reiterate: Awesome work!!! Reading your post gave me goosebumps and put a huge smile on my face.

---

<div class="post-metadata">

**Author:** ![wolfadex](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/wolfadex/32/2461_2.png) [@wolfadex](https://discourse.elm-lang.org/u/wolfadex)\
**Post date:** [June 9, 2026, 5:42pm UTC](https://discourse.elm-lang.org/t/run-native-elm-on-your-server-and-your-terminal-yes-native/10747/15 "2026-06-09T17:42:39Z")

</div>

> [@john\_s](#):
>
> If there are packages that are only available on this platform then doesn’t that fragment Elm a little and so change Elm?

> [@john\_s](#):
>
> How will we organize and discover packages that work in the browser, as a CLI, as a native server, as a game?

We already have this and I don’t feel that it’s impacted the community in a negative way. [elm-pages 12.3.0](https://package.elm-lang.org/packages/dillonkearns/elm-pages/latest/) isn’t really usable outside of building an elm-pages app or script. There’s also a variety of packages that require pairing with a JS script for introducing things like web components, e.g. [elm-canvas 5.0.0](https://package.elm-lang.org/packages/joakin/elm-canvas/latest/).

Separately, the vast majority of Elm code is pure functions. The thing that differentiates one Elm platform from another is how it handles effects. In this case, elm-run requires capability arguments for a lot effect related functions, so a package which has the type

```elm
foo : Fs.Stdin -> ??? -> ???

```

can only be used if you’re in the context of an app that provides `Fs.Stdin` as a type. This is very similar to how browser navigation works in Elm today, that requires a `Browser.Navigation.Key` which today we only get from [browser 1.0.2](https://package.elm-lang.org/packages/elm/browser/latest/) and [elm-program-test 4.0.1](https://package.elm-lang.org/packages/avh4/elm-program-test/latest) (maybe 1 or 2 other pacakges).

Like I could see a future where elm-ui renames [Element.layout](https://package.elm-lang.org/packages/mdgriffith/elm-ui/latest/Element#layout) to `Element.toHtml`, and adds `Element.toTui` and `Element.toView` which respectively return `Terminal.Tui.View.View msg` and `some native graphical type`. This would make elm-ui 99% _just Elm code_ and then there’d be 3 platform specific functions for converting to the appropriate platform type.

* * *

Just my own opinions/thought

---

<div class="post-metadata">

**Author:** ![john\_s](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/john_s/32/4425_2.png) [@john\_s](https://discourse.elm-lang.org/u/john_s)\
**Post date:** [June 9, 2026, 6:12pm UTC](https://discourse.elm-lang.org/t/run-native-elm-on-your-server-and-your-terminal-yes-native/10747/16 "2026-06-09T18:12:29Z")

</div>

True.

On the one hand, I get the larger point that the question of platform reduces away to module dependencies because platform capabilities are only exposed through module Apis. There are islands of libraries that depend on elm-ui and only work in that sub ecosystem. It can be viewed as just another species of tree analysis. Totally. Very elegant and all. One can say: "Let’s not solve this as a problem of discovering ‘platform’ things but rather let’s extend our package search system to show packages with a common transitive dependency i.e. show me only packages that require X and which don’t require Y.

On the other hand, I think that the size and nature of elm-run’s differentiation is more significant and could therefore justify a commensurate solution. This is really a question of the Fairbairn threshold. Given it can be viewed as a dependency tree problem do we simply ask users to use that general set of primitives to solve their problem? Or is a specific facade justified? Of course, it can be both.

I am really glad to hear that you don’t feel this is a threat to the uniformity of the community (by the way, I am very happy Lamdera user and that is itself a small platform). I asked because this community is generally very strongly in favor of keeping things the Elm way and I was hoping that this wouldn’t create a sense of fragmentation. One thing I detest about TypeScript is that it is so balkanized that it drives combinatorial explosions in configuration complexity. You have CommonJS, AMD, UMD, ESNext. You have different module resolutions. The command line compiler disagrees _often_ with the IDE language service which disagrees _often_ with the run-time behavior. Then there are tools to tie those things together and make them whole, but then those tools don’t work together and you need tools to connect those tools to the other tools… and it becomes the old [Now there are 15 competing standards](https://xkcd.com/927/) joke. The point being that I am very slightly suspicious of anything that could push Elm off that cliff. That said - we are nowhere near the edge at this point.

---

<div class="post-metadata">

**Author:** ![damir](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/damir/32/5549_2.png) [@damir](https://discourse.elm-lang.org/u/damir)\
**Post date:** [June 9, 2026, 9:31pm UTC](https://discourse.elm-lang.org/t/run-native-elm-on-your-server-and-your-terminal-yes-native/10747/17 "2026-06-09T21:31:59Z")

</div>

@john_s good questions!

You answered it yourself: being able to do so much more without changing the language. That’s the goal. Of course, “doing so much more” also means “not doing the exact same thing,” so now we can split hairs over how that Venn diagram looks like.

A web server programmed exactly like Elm with `init`, `update`, `subscription` and exact same idioms we learned in Elm in the Browser is still Elm. Unchanged. Yes, it changes what you _do_: you are programming a web server, a different beast from the browser. You’re writing `Http.respond` instead of `Http.request`. But you’re still doing web, still using exact same compiler that will let you write exact same language and nothing more.

If you did 10 hours of Elm for the Browser a week, and now you’re down to five and the other five programming the web server, then yeah, you’re splitting your time, and your vision of “what can this language do for me” certainly changed. But you’re still doing 10 hours of Elm programming.

Or suddenly you’re doing 20 hours, playing with **Elm Game**'cause it’s so much fun! Means I did my job and drove up cumulative usage hours of Elm!

I decided the compiler is the yardstick for “the same thing.” The compiler guarantees it’s still the same language. That’s why I went to insane lengths to keep using the same compiler. Probably 1/3 of total effort went into ensuring that I can deliver a usable runtime over that unchanged compiler. Could have rewritten it twice in that time! Would have been way easier. But it wouldn’t have been the same thing. In my product strategy, everything up and to the left of that “`run` optimizer” in the diagram is not for debate. Unquestionable.

It’s a deliberate move, a very expensive signal that I’m not here to fragment the community; only enlarge.

The package stuff you speak of is a non-issue, really. My intent with the whole distribution business goes way beyond **elm-run** described here. Hopefully the few here who read the draft chapter of the web server book saw the first hint. You maybe don’t know that I started working on [**elm-wrap**](https://elm-wrap.dev) before I had the idea for **elm-run**. Like here, it extends what you can do without taking away from what you could do. Software distribution is my deep concern, and I delivered so far maybe 15% of the vision. With all this stuff coming up, I don’t think you’ll be concerned about “package fragmentation cliff.”

I started writing about my strategy to prevent balkanization, but let’s leave that for another post. You won’t believe me, anyway.

`"🙂"` Keep on smiling!

---

<div class="post-metadata">

**Author:** ![rupert](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rupert/32/1775_2.png) [@rupert](https://discourse.elm-lang.org/u/rupert)\
**Post date:** [June 10, 2026, 4:49pm UTC](https://discourse.elm-lang.org/t/run-native-elm-on-your-server-and-your-terminal-yes-native/10747/18 "2026-06-10T16:49:35Z")

</div>

> [@wolfadex](#):
>
> Separately, the vast majority of Elm code is pure functions. The thing that differentiates one Elm platform from another is how it handles effects. In this case, elm-run requires capability arguments for a lot effect related functions, so a package which has the type  
> foo : Fs.Stdin → ??? → ???
> 
> can only be used if you’re in the context of an app that provides Fs.Stdin as a type.

In this article linked from the most recent Elm News Letter:

> **[Is this production-ready? Link to heading - Native Elm (the real kind this time)](https://cekrem.github.io/posts/native-elm/?utm_source=substack&utm_medium=email#is-this-production-ready)**
>
> Back in December I hacked Elm onto a Node.js backend and got a little carried away calling it “Elm on the backend.” It wasn’t, really. Node did all the actual work – opened the socket, parsed the HTTP, wrote the response – and Elm sat in the middle...

It says:

> the “host” concept the authors now call a bit of a kludge they’re planning to tear out

I think what he is talking about here, the “host” concept, is this capability argument (Fs.Stdin), but a bit unsure.

Anway, what I wanted to ask is, do you plan to keep this for the long term ? Or will it as cekrem claims, be ripped out and replaced with some other mechanism to enable “capabilities”, such as package tagging for example ? Would keep the IO APIs cleaner.

---

<div class="post-metadata">

**Author:** ![wolfadex](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/wolfadex/32/2461_2.png) [@wolfadex](https://discourse.elm-lang.org/u/wolfadex)\
**Post date:** [June 10, 2026, 5:24pm UTC](https://discourse.elm-lang.org/t/run-native-elm-on-your-server-and-your-terminal-yes-native/10747/19 "2026-06-10T17:24:40Z")

</div>

I think [Browser.Navigation - browser 1.0.2](https://package.elm-lang.org/packages/elm/browser/latest/Browser-Navigation) is an interesting example/test case. The top half of the functions in the module can only be run from within `Browser.application`, while the bottom half can be run from anywhere. There’s nothing preventing `Browser.Navigation.load` from being called from within `Platform.worker`. If that app is running from within Node, that function call makes no sense!

So `Browser.Navigation` already demonstrates both sides of the situation, both with and without a capabilities approach.

I wonder how else this can be accomplished, both from an academic perspective and practical, the restricting of functions to within a particular program.

My personal take, right now, is that the passing of a capability/key is very explicit, which feels very Elm-ish. It does require extra work, but it makes it very clear about what is happening. As I’ve been playing for the past week, I’ve been doing a lot of acquiring/checking presence of appropriate capabilities and then passing them around. Right now that means passing around a lot of arguments.

I’ve also learned from changes @miniBill has made to elm-open-api-cli over the years (specifically the `CliMonad a`) as well as Elm Land changes and the work @jfmengels has been doing with the elm-review refactor, and I can very much see myself refactoring away from rudimentary `Task e a` and the like to something specific to each app. I can see capabilities working with with this style of change.

And I think I’m starting to ramble a bit so I’ll leave it at that.

---

<div class="post-metadata">

**Author:** ![rupert](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rupert/32/1775_2.png) [@rupert](https://discourse.elm-lang.org/u/rupert)\
**Post date:** [June 10, 2026, 5:52pm UTC](https://discourse.elm-lang.org/t/run-native-elm-on-your-server-and-your-terminal-yes-native/10747/20 "2026-06-10T17:52:53Z")

</div>

> [@wolfadex](#):
>
> I wonder how else this can be accomplished, both from an academic perspective and practical, the restricting of functions to within a particular program.

One way it could be accomplished could be by tagging packages with capabilities. But this would mean they are course grained at the package level.

So for your `Fs` example, suppose the package elm-run/file-system is tagged “fs” - that would mean it supplies or requires the filesystem capability. Then I write some new package rupert/stuff that does some stuff with files, and I have to tag it “fs” in order to consume elm-run/file-system, which in turn means that if you want to use my package, you also need the “fs” tag. So any application built on rupert/stuff and transitively on elm-run/file-system needs to be tagged “fs” and that would be what unlocks the capability and lets you use it.

But I also notice in your example you used the capability key “Fs.Stdin” which suggests to me that these capabilities are intended to be more fine-grained than the package level.

This reminds me of the Java security properties mechanism: [The Security Properties File](https://docs.oracle.com/en/java/javase/24/security/security-properties-file.html) - which lets you permit/deny capabilities to the platform, and proofs can be extracted from bytecode that the properties cannot be violated.

Which suggests another way of doing it - to not explicitly pass capability keys, but to check bytecode against the local settings. If a Task attempts to do something it is not permitted to, crash/fail/ignore.

[Next page](https://discourse.elm-lang.org/t/run-native-elm-on-your-server-and-your-terminal-yes-native/10747.md?page=2)
