# Elm programs that don't die

**URL:** <https://discourse.elm-lang.org/t/elm-programs-that-dont-die/10377>\
**Category:** Show and Tell\
**Created:** [August 7, 2025, 4:44pm UTC](https://discourse.elm-lang.org/t/elm-programs-that-dont-die/10377 "2025-08-07T16:44:02Z")\
**Posts on this page:** 4\
**Page:** 1

<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:** [August 7, 2025, 4:44pm UTC](https://discourse.elm-lang.org/t/elm-programs-that-dont-die/10377/1 "2025-08-07T16:44:02Z")

</div>

There are times when you want to kill an Elm program good and proper. A reason for this is that Elm programs don’t always clean themselves up how you would expect. Especially if you are using Elm in a fairly custom way like with a framework.

[Djelm](https://github.com/Confidenceman02/django-elm), a framework I built for seamlessly using Elm in the Django web framework, does a few tricks and sleight of hand to achieve its goal of hydrating Elm programs client side from server generated html Django pumps out.

If you have a simple MPA, there are no issues at all, you load a page, the page resets the state, djelm runtime hydrates any included Elm programs, happy days!

If however you use a slightly more modern approach like HTMX to get that sweet SPA experience then things kinda start hanging around. You load a page, but now HTMX gets involved and instead of a fresh new page, you get the same page you were on, just with the new html spliced in and the url changed to reflect the new route. It’s wonderful but here be dragons.

What happened to the Elm programs from the previous page? Well, there was no fresh page loaded so those programs are actually still alive and holding on to memory, it’s just that they aren’t connected to DOM. If one of those programs was fetching data from the server every 5 seconds then the chances are, it still is!

Frameworks like elm-pages and Lamdera almost certainly have to deal with this scenario, as does djelm.

[Djelm](https://github.com/Confidenceman02/django-elm) works around this by patching compiler output at bundle time. Internally [djelm](https://github.com/Confidenceman02/django-elm) uses [Parcel](https://github.com/parcel-bundler/parcel) so I wrote [@confidenceman02/parcel-transformer-djelm](https://www.npmjs.com/package/@confidenceman02/parcel-transformer-djelm) to do the job. Parcel simply calls my transformer when it sees Elm code then the transformer handles the compilation and patching. This was massively inspired by the very excellent [@parcel/transformer-elm](https://www.npmjs.com/package/@parcel/transformer-elm)

What it does is adds a ‘die’ hook, an idea I stole from this [gist](https://gist.github.com/supermario/4c2615806c6c561a16edf5dd7208a759) with some modifications. Now, the program’s internal references can be nulled out and memory garbage collected. You can read more about it in djelm’s JS interop section in the [README](https://github.com/Confidenceman02/django-elm?tab=readme-ov-file#js-interop).

Oddly enough it’s been a real treat working on this. It takes you in to the parts of Elm that are less visible but so very interesting.

---

<div class="post-metadata">

**Author:** ![lydell](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/lydell/32/178_2.png) [@lydell](https://discourse.elm-lang.org/u/lydell)\
**Post date:** [August 10, 2025, 12:16pm UTC](https://discourse.elm-lang.org/t/elm-programs-that-dont-die/10377/2 "2025-08-10T12:16:24Z")

</div>

Cool!

I happen to have been working on stopping Elm programs recently, too. I want to add it to the elm/\* packages directly, no patching needed. While doing that, I learned that the `die` function from the gist you linked treats symptoms rather than the underlying issue. But that’s better than nothing! I’ll get back to that below.

At the same time, I’ve worked on bringing the hot reloading capability from [elm-watch](https://lydell.github.io/elm-watch/) to elm/\* packages, so all tools – including yours – can benefit from it. I saw you have an [issue about adding elm-hot](https://github.com/Confidenceman02/django-elm/issues/39) so I thought you’d be interested in that, too.

I’ve built the app hot reloading and stopping on top of my [elm-safe-virtual-dom](https://github.com/lydell/elm-safe-virtual-dom) project (which I haven’t announced fully yet, but anyway). Follow that link to learn how forked elm/\* packages can be installed.

I’m currently [integrating my work with Lamdera](https://github.com/lamdera/compiler/pull/65). The Lamdera team has expressed interest in shipping my forked elm/\* packages by default. Note that the Lamdera Compiler is open source and can be used for vanilla Elm programs. Several community members have started contributing to it.

All in all, there is a potential future where you get both app stopping and hot reloading for free (with a side bonus of a virtual DOM that doesn’t crash as easily). Maybe via the Lamdera Compiler.

Now, back to “treating the symptom rather than the underlying issue”. A `Platform.worker` program without any ports (yes, that’s a useless program, but anyway) can actually stop already. But anything other than that have a few problems:

- elm/virtual-dom needs to provide a way to remove all event listeners from the DOM, and be able to stop `main : Html msg` programs: [Make it possible to stop an app · lydell/virtual-dom@edad688 · GitHub](https://github.com/lydell/virtual-dom/commit/edad68883bcb501bd1f5d3e831acdf427b5ba561)
- `Browser` programs need to use the above to remove event listeners from the DOM, and `Browser.application` needs to remove its `popstate` listener along with a garbage collecting preventing reference: [Make it possible to stop an app · lydell/browser@2b7e9d4 · GitHub](https://github.com/lydell/browser/commit/2b7e9d412ee6bdc270dde60091a5747eb328e85f)
- elm/core needs to make use of the above, and provide convenience for stopping update and subscriptions: [Make it possible to shut down an app · lydell/core@4726168 · GitHub](https://github.com/lydell/core/commit/47261689e668ebf47039bddd3953dd49b87db197)
- elm/core also needs to fix two “bugs” preventing garbage collection: [Fix memory leaks via ports and subscriptions · lydell/core@157cf9e · GitHub](https://github.com/lydell/core/commit/157cf9e95116f381741088abbd542b6c9b35213c)

For more details, read [how app stopping and hot reloading works](https://github.com/lydell/core/blob/53747f003cb40a0bc1ad2901d475099c038a2bcc/javascript-interface.md#appstop).

I plan to make PR:s to the elm/\* repos when I feel finished, for increased visibility. (I’ve already created PR:s for my elm-safe-virtual-dom stuff.)

Finally, in case someone is curious how to test and debug garbage collection: Use [Chrome’s Memory devtools](https://developer.chrome.com/docs/devtools/memory-problems/get-started). I put a ridiculously big field in the model (`List.range 0 100000 |> List.map (\i -> { a = String.repeat i "a", b = i })`, around 50 MiB) and check if memory usage goes down after stopping the app. If not, I take a memory snapshot, sort objects by memory size and check the “Retainers” to see what’s holding on to the model. It’s not super easy, but much better than shooting in the dark.

---

<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:** [August 10, 2025, 3:27pm UTC](https://discourse.elm-lang.org/t/elm-programs-that-dont-die/10377/3 "2025-08-10T15:27:13Z")

</div>

Thanks so much for this great explanation, it was thorough and very well documented. Really impressive work!

Im definitely going to steal the `VirtualDom_removeAllEventListenersHelp(tNode)` code as that was absolutely a head scratcher for me.

Adding the `$__shutdown` on the stepper is super clever and that means I can just call it from my die code and remove all event listeners from the tree, which is a huge improvement.

It would be lovely to not need to brute force the code in to the compiler output so I’m definitely keen for a “it just works” solution. Especially HMR.

I’ll follow your progress!

---

<div class="post-metadata">

**Author:** ![system](https://canada1.discourse-cdn.com/flex035/uploads/elm_lang/original/1X/50a05e53677a2c3b47776d7abd0f113eb50193a1.png) [@system](https://discourse.elm-lang.org/u/system)\
**Post date:** [August 20, 2025, 3:28pm UTC](https://discourse.elm-lang.org/t/elm-programs-that-dont-die/10377/4 "2025-08-20T15:28:05Z")

</div>

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.
