Announcing elm-spa: version 6.0.0 🎉!

Hey, folks! :wave:

I’ve got some exciting news to announce:

The latest version of elm-spa has just been released! :tada:

The new elm-spa homepage

Why use elm-spa?

If you’ve ever glanced at a previous version of elm-spa and thought “uhhh… maybe later”: I strongly encourage you to check out this latest design!

I think you’ll be delightfully surpised by how far the project has come along!

A focus on welcoming beginners

The JS ecosystem has amazing projects like Vue’s Nuxt.js or React’s Next.js. These projects make it easy to build an app from scratch, and provide conventions for newcomers to follow.

One of my biggest design goals for the latest release was to make it easy for new folks to get started. You can get a project spun up in a single command!

Even better, it only creates three new files:

  1. An elm.json
  2. A public/index.html entrypoint
  3. This elm file:
module Pages.Home_ exposing (view)

import Browser
import Html

view : Browser.Document msg
view =
    { title = "Homepage"
    , body = [ Html.text "Hello, world!" ]

The elm-spa CLI takes care of all the extra boilerplate for you! :sparkles:

The CLI also comes with a built-in dev server, kinda like elm reactor for single page apps!


  • Automatic routing - elm-spa generates URL parsers and page boilerplate for you under the hood
  • User authentication - The new Auth.elm file makes it easy to guarantee only signed-in users have access to certain pages
  • Zero configuration CLI - The CLI has been slimmed down and comes with its own dev server, build commands, and scaffolding tools. ( Also designed to play well with other dev servers )
  • That website tho - The latest website has plenty of guides and examples to get you started with your next single page application!

Should I upgrade from v5?

“Oh heck yeck!” - my (totally unbiased) advice

Here are a few reasons to upgrade:

  • User authentication is no longer spooky
  • Easier API for sharing state across pages
  • Easier to work with elm-program-test and elm-test
  • Less boilerplate all round!

You should take a look at this RealWorld example app PR where I completely upgraded from elm-spa@5 in less than an hour. I just followed those friendly Elm compiler messages to victory! :muscle:

Try it out, share those feels!

I’ve been iterating on the design for v6 for a while, and would love to hear your initial thoughts and impressions on how easy it was for you to get started.

Helpful links:

Thanks for reading!



Awesome, been eagerly anticipating this this! Congrats on the release!

1 Like

Looks great!

I would suggest promoting the release in the Github Releases section of the repo, as the “latest release” there is an old tag. Releases · ryannhg/elm-spa · GitHub

1 Like

This is amazing and I’ll use it for my next project!

Small feedback: in the spirit of being friendly to newcomers, maybe write somewhere that the protected page are still visible in the javascript, to avoid people being mistaken into thinking they aren’t

1 Like

Looks great!

I like the defaults/ and “eject” mechanism. Amazing how this keeps getting simpler to use.

Also like we can now send messages again to the shared module.

I do have one question – where is Effect defined?

update : Msg -> Model -> ( Model, Effect Msg )
update msg model =
    case msg of
        ClickedSignOut ->
            ( model
            , Effect.fromShared Shared.SignOut
1 Like


Within the .elm-spa/defaults folder.

If you need to customize it, you can drag it to the src folder :open_file_folder:

This is awesome, congrats on this release!

Reading through the guide, I’m really digging the simplicity of the selective ejecting technique!

So far I’ve seen other tools with an eject functionality, but those were always a binary choice.
What was your inspiration for this feature? Is this technique used in other popular tools I don’t know about?

I have a question about the Page.protected mechanism. Does this have to be a “user”? Or could I also “protect” pages to require the presence of some other state? E.g. my application might not make sense before configuring a user defined API server URL, so all pages that require this state should be “protected”.
Would this protected pages feature make sense for this use case too?


@zinggi your intuition is right! You can provide any type of value to those protected pages, it doesn’t have to be a user!

You’ll still get the guarantee that protected pages will definitely have access to whichever value you’d like them to have.

You can even conditionally redirect to different routes, in the case where you do have signed a user but they should be redirected to a permission denied page.

Great, that’s definitely what I need then.
Before this announcement I was toying with the idea of creating my own custom runtime (a la Blog: Design your own Runtime) to make those guarantees for a new project. I was also gonna use the effects pattern and would have made some other similar choices.

But after your announcement, I don’t have to, elm-spa seems to cover all my needs already! And much simpler than anything I could have come up with.

Again, congratulations on achieving such simplicity!

1 Like

Congratz on release! Some quick feedbacks:

  • As people saying, selective eject is really a neat idea :+1:
  • Pages.advanced => Pages.protected.advanced upgrade path is concise and friction-less :heart:
  • A bit of confusion on upgrading existing lower-complexity pages (like static) to higher ones (advanced). Eventually I figured out to perform elm-spa add /xxx advanced but the progress on existing page is overwritten. I’m missing somthing, or the doc might need mentioning on that.
  • Code-generation by elm-spa server/watcher and on-the-fly diagnostics by ElmLS is kinda conflicting. Since recent ElmLS on-the-fly diag runs quite fast by its own (without speaking to elm make), it reports faster than elm-spa-managed file generations. Resulting in frequent error emissions (like Gen.Pages.XXX modules not found.) Though this might better be redirected to @razze @jfmengels (perhaps configurable delay on on-the-fly diags?)

Overall it looks very promising! Somthing that I would like to hear is:

  • API stability: do you think current elm-spa API is maturing enough, or still foreseeing some non-trivial evolution?
  • What is the recommended approach to adopt elm-spa to existing non-elm-spa Elm apps? That could be quite valuable hook to this tool! (Though such a thing is THE part where the community including myself have a great chance to bring ideas in :stuck_out_tongue_winking_eye:
1 Like

Forgot to add: assertable (elm-program-test-able) layer of Effect is definitely a wise choise to add!
It certainly is a non-trivial step from elm-guide for beginners, but helps us in a long run.


This is very a wonderful project.
I have an elm-ui SPA of mine which seems to fit perfectly to be rewritten with elm-spa.

1 Like

Hi Ryan, I am enjoying the library but have been unable to understand the perhaps of the Redirecting_ Msg or the View.none method. How are we to use these?

Hi Ryan, this is awesome. We are using it to build a project and upgraded to v6.

I was wondering what you consider best practice for updating the shared model from a page.

Currently, we have a SetSharedModel (Model -> Model) shared msg that we fire using Effect.fromShared

( model, Shared.SetSharedModel (\sm -> { sm | myField = newValue } |> Effect.fromShared )

Is this how you would do it?

@Nduati_Kuria and @tlentz thank you both for the kind words!

You should join the official #elm-spa-users slack channel and ask the wonderful folks there questions like these. I randomly check Discourse, so you’ll receive more timely responses to questions like the ones in this thread.

But since I’m here anyway, I might as well answer these two questions :smiley: :

If you mean redirecting users that aren’t signed in, check out the user authentication example. If you mean redirecting in general you can learn more about Programmatic Navigation in the request guide.

A default View.elm implementation is generated for you in the .elm-spa/defaults folder. You can learn more about customizing that file in the view guide.

It’s ultimately up to you on how to update the Shared.Model in your app, but I would recommend creating a Shared.Msg for each shared action you’d like to perform, and pass those messages to Effect.fromShared.

This means Shared.update can handle all your logic in one place.

The local storage example is actually an interesting way to share state between pages without needing Page.advanced at all. You can use Cmd msg for all the things! This strategy also makes your data is available on refresh, so it doesn’t disappear on you when you close the tab. ( Personally, that’s my favorite way to handle shared state, but I added in Effect.fromShared because it’s a lot more intuitive and easy to work with. )

Thanks everyone for the good vibes!

I’m so glad to see the project is getting folks excited to build cool stuff.

If you make something cool with elm-spa, please share it with the community! I personally love seeing stuff like that, and it sure beats discovering another thread about typeclasses.


I also just migrated my own website from 5 to 6. Took me a few hours spread across three evenings.

Initially I was struggling a bit with setting up the correct “framing”, figuring out where to put the shared stuff and the shared view. The thing with “there are default generated files and you can move them over if you modify them” didn’t click with me for a while. I also wasn’t sure what old code to remove and which old code to keep. I should definitely set up elm-review next to see which unused code can still be deleted.

Was really happy once I got the website compiling again, even though I had lost all the shared ui and the load/store methods. But getting those back afterwards wasn’t so hard :smiley:

Thanks for your work providing this framework library!


@RyanNHG Thanks a lots for this library, i upgrade my current project from 5 to 6 last night, so nice, once you convert your first Page :wink: I have to migrate the save function to get some feature back, but overall the experience has been quiet good. It’s nice to see Elm SPA design improvements. Thanks for your effort, I think i learn a lots be reading your guides and code.

1 Like