The words in parens are the Redux equivalents of the Elm concept they are next to. This article describes these differences in more detail and compares the equivalent code in both.

If They’re The Same, Why Consider Elm?

There have been a lot of articles recently about moving away from Redux. The consensus seems to be that the Redux Pattern can make code more maintainable and reduce data synchronization bugs, but the cost is too high because it requires so much boilerplate. So many people are recommending using the same patterns without the Redux library itself (including Dan Abramov, the original author of Redux; see this post as well).

But there’s another option! With Elm, the patterns of Redux are built into the language itself (not an optional library or framework). That means that it’s a lot more natural because the language is literally built for creating apps using that pattern. It also means no “JavaScript Fatigue” because Elm is opinionated about its data store. So no updating to the flavor-of-the-month data store (and a custom set of supporting libraries). Plus, you have to deal with a lot less boilerplate, and you have the famously helpful Elm compiler helping you avoid bugs!

Comparing Elm and Redux

This guide is meant to bridge the gap and help you learn Elm by leveraging the knowledge you already have about Redux. We’ll compare basic Counter apps in both paradigms. This isn’t meant to be a comprehensive comparison, but rather a basic intro to the fundamentals.

Here are the full code examples used throughout this guide:

⚛ Live Example in Redux

🌳 Live Example in Elm

(The Redux example is in a single file for easy comparison; see this codesandbox for the same example split into multiple files).

Initializing and Updating State

⚛ Redux Reducers, 🌳 Elm update and init functions

⚛ Redux Reducer

🌳 Elm update / init functions

Notice that we have to have a default case in Redux. Since action.type is just a string it could be anything. Often tools like TypeScript or Flow are used to help make sure we are handling each valid case and don’t have any typos or incorrect assumptions about the Redux event payloads.

Using just Vanilla Elm, the compiler gives you these guarantees. And there are no escape hatches like TypeScript’s any type, so if your program runs you are guaranteed that there will be no unhandled cases or runtime exceptions.

Triggering Events

⚛ Redux Actions, 🌳 Elm Messages ( Msg )

⚛ Redux Actions

🌳 Elm Messages ( Msg )

Notice that in Elm, there is no wiring to manually dispatch actions as there is in Redux. In React, onClick takes a function, so you manually wire it up to call store.dispatch(...) in the function you pass to onClick . Elm assumes an architecture where you the only thing you can do from an onClick (or any other event) is dispatch an action (or Msg in Elm lingo). So this is simpler and less error prone in Elm. You just declaratively give an onClick Increment and The Elm Architecture takes care of the wiring to dispatch the Increment Msg at the appropriate time. This is one of the big benefits of having the data architecture built into the language. It’s also type-safe, which you’ll appreciate a lot more when you’re working with a large scale app and not just a toy example like this! That guarantees that every Msg has exactly the data you said it would, and that you have handled every possible Msg (and only possible Msg s).

Also notice that there is no need for anything like PropTypes in Elm to give you warnings when you forget to pass fields or pass in the wrong data type. This is built with Elm’s famously helpful compiler and type system!

HTML Templating