by ThomasWeiser

ThomasWeiser / elmfire

Firebase Bindings for Elm

215 Stars 16 Forks Last release: Not found Other 84 Commits 9 Releases

Available items

No Items, yet!

The developer of this repository has not created any items for sale yet. Need a bug fixed? Help with integration? A different license? Create a request here:

ElmFire: Use the Firebase API in Elm

Virtually all features of the Firebase Web API are exposed as a library for Elm:

  • Setting, removing and modifying values
  • Transactions
  • Querying data, both one-time and per subscription
  • Complex queries with sorting, filtering and limiting
  • Authentication
  • User management
  • Offline capabilities

In addition to these base functions the package elmfire-extra provides a higher-level synchronization API, which allows you to treat your Firebase data like a local Elm-Dict.

Demo application for these APIs: Collaborative TodoMVC

This library currently targets Elm version 0.16.

A new version with an effect manager for Elm 0.17/0.18 is under development. Please stay tuned!

API Usage

The API design corresponds closely to the targeted Firebase JavaScript API. Please refer to the original documentation for further discussions of the concepts.

In the following we give a short overview of the API. Detailed documentation is embedded in the source code.

Constructing Firebase Locations

To refer to a Firebase path use a

. It can be built with the following functions:
-- Location is an opaque type.
fromUrl  : String -> Location
sub      : String -> Location -> Location
parent   : Location -> Location
root     : Location -> Location
push     : Location -> Location
location : Reference -> Location

These are all pure functions. They don't touch a real Firebase until the resulting location is used in one of the tasks outlined below.


location : Location
location =
  fromUrl "https://elmfire.firebaseio-demo.com/test"
    |> parent
    |> sub "anotherTest"`
    |> push

References to Locations

Most actions on a Firebase location return a reference to that location. Likewise, query results contain a reference to the location of the reported value.

References can inform about the key or the complete URL of the referred location. And a reference may be converted back to a location, which can be used in a new task.

There is a special task to open a location without modifying or querying it, which results in a reference if the location is valid. It's generally not necessary to explicitly open a constructed location, but it may be used to check the validity of a location or to cache Firebase references.

-- Reference is an opaque type
key      : Reference -> String
toUrl    : Reference -> String
location : Reference -> Location
open     : Location -> Task Error Reference

Modifying Values

set             : Value -> Location -> Task Error Reference
setWithPriority : Value -> Priority -> Location -> Task Error Reference
setPriority     : Priority -> Location -> Task Error Reference
update          : Value -> Location -> Task Error Reference
remove          : Location -> Task Error Reference

These tasks complete when synchronization to the Firebase servers has completed. On success they result in a Reference to the modified location. They result in an error if the location is invalid or if you have no permission to modify the data.

Values are given as Json values, i.e.



port write : Task Error ()
port write =
  set (Json.Encode.string "new branch") (push location)
  (\ref -> ... ref.key ... )


Atomic modifications of the data at a location can be achieved by transactions.

A transaction takes an update function that maps the previous value to a new value. In case of a conflict with concurrent updates by other clients the update function is called repeatedly until no more conflict is encountered.

transaction : (Maybe Value -> Action) ->
              Location ->
              Bool ->
              Task Error (Bool, Snapshot)
type Action = Abort | Remove | Set Value


port trans : Task Error -> Task Error ()
port trans =
    ( \maybeVal -> case maybeVal of
        Just value ->
          case Json.Decode.decodeValue Json.Decode.int value of
            Ok counter -> Set (Json.Encode.int (counter + 1))
            _          -> Abort
        Nothing ->
          Set (Json.Encode.int 1)
    ) location False
  (\(committed, snapshot) -> ... )


once        : Query -> Location -> Task Error Snapshot
subscribe   : (Snapshot -> Task x a) ->
              (Cancellation -> Task y b) ->
              Query ->
              Location ->
              Task Error Subscription
unsubscribe : Subscription -> Task Error ()


to listen to exactly one event of the given type.

The first parameter specifies the event to listen to:

. Additionally, this parameter may also specify ordering, filtering and limiting of the query (see below). If you don't need these options a simple query specification is
valueChanged noOrder

The second parameter references the queried location.


to start a continuing query of the specified events. Subscription queries return a arbitrary number of data messages, which are reported via running a supplied task.

The first parameter of

is a function used to construct that task from a data message.

The second parameter is a function used to construct a task that is run when the query gets canceled.

The third and fourth parameter of

are the same as the first two of

On success the

task returns a Subscription, an identifier that can be used to match the corresponding responses and to cancel the query.
type alias Snapshot =
  { subscription: Subscription
  , key: String
  , reference: Reference
  , existing: Bool
  , value: Value
  , prevKey: Maybe String
  , priority: Priority
type Cancellation
  = Unsubscribed Subscription
  | QueryError Subscription Error


carries the resulting
(as Json) among other information, e.g. the corresponding

In queries of type

the result may be that there is no value at the queried location. In this case
will be
and value will be the Json value of

corresponds to the last part of the path. It is the empty string for the root. Keys are relevant notably for child queries.


responses : Signal.Mailbox (Maybe Snapshot)
responses = Signal.mailbox Nothing

port query : Task Error Subscription port query = subscribe (Signal.send responses.address << Just) (always (Task.succeed ())) (childAdded noOrder noLimit) (fromUrl "https:...firebaseio.com/...")

... = Signal.map (\response -> case response of Nothing -> ... Just snapshot -> ... ) responses.signal

Ordering, Filtering and Limiting Queries

Query results can be ordered (by value, by a child's value, by key or by priority), and then filtered by giving a start and/or end value within that order, and limited to the first or last certain number of children.

Example queries to be used in

childAdded noOrder
childAdded (orderByValue noRange noLimit)
childAdded (orderByChild "size" noRange noLimit)
childAdded (orderByKey noRange noLimit)
childAdded (orderByPriority noRange (limitToFirst 2))
childAdded (orderByValue (startAt (Json.Encode.string "foo")) noLimit)
childAdded (orderByValue (startAt (Json.Encode.string "foo")) (limitToLast 10))
childAdded (orderByChild "size" (equalTo (Json.Encode.int 42)) noLimit)
childAdded (orderByKey (endAt "k") noLimit)
childAdded (orderByPriority (startAt (NumberPriority 17, Just "k")) noLimit)

When doing ordered

queries it may be useful to map the result to a list to conserve the ordering:
toSnapshotList : Snapshot -> List Snapshot
toValueList    : Snapshot -> List JE.Value
toKeyList      : Snapshot -> List String
toPairList     : Snapshot -> List (String, JE.Value)


The sub-module ElmFire.Auth provides all authentication and user management functions that are offered by Firebase.

Some example tasks:

import ElmFire.Auth exposing (..)

-- create a new user-account with email and password userOperation (createUser "[email protected]" "myPassword")

-- login with with email and password authenticate loc [rememberSessionOnly] (withPassword "[email protected]" "myPassword")

-- login with with github account authenticate loc [] (withOAuthPopup "github")

-- watch for logins and logouts subscribeAuth (\maybeAuth -> case maybeAuth of Just auth -> ... auth.uid ... Nothing -> ... -- not authenticated ) loc

Offline Capabilities

  • Detecting connection state changes:
  • Manually disconnect and reconnect:
  • Managing presence:
  • Handling latency:


There is a basic example app in

. To build it:
cd example
make all open

Alternatively without using

cd example
elm make --output Example.html src/Example.elm


A more extensive example is this implementation of TodoMVC as a collaborative real-time app.


There is a testing app, living in the directory

, that covers most of the code. It runs a given sequence of tasks on the Firebase API and logs these steps along with the several results.

This app uses a small ad-hoc testing framework for task-based code.

There is a Makefile to build the app. On most Unix-like systems a

cd test; make all open
should do the trick.

An older, still functional testing app lives in the directory


We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.