elm christmas

Publishing packages

←Previous postNext post →

Christmas is a time for sharing (ideas and code)

A 5 min read written by
Ingar Almklov

While creating your latest application in Elm you discovered some neat functionality that you want to share with the community. Sadly you have never published a package before so you don't know where to start. Well, look no further! Today we'll guide you through the process.

The inception

Let's start by taking a step back.

One part of the Elm "philosophy" is that it is better for users (developers) to have one great option instead of twenty mediocre ones. This is great as it is easier to pick a package and get started. For example if you want do render some HTML you use elm/html. If you want to fetch something over HTTP you use elm/http. If you want to test your code you use elm-explorations/test.

For this reason it is often recommended to discuss your package idea with the community before publishing. Maybe what your package tries to achieve can be done with an existing package? Maybe you can contribute to an existing project to get support for the functionality you need? Maybe someone has the same needs as you do and you can join efforts to create the most awesome solution ever?!

Still, this isn't to say that you should not experiment with new ideas! New ideas are always welcome and innovation is important in a healthy package ecosystem. Just remember how it is to be a consumer. It is hard choosing between four different packages, each with varying degrees of documentation, that all seem to solve the same problem. This may be a bit subjective, but I far prefer having one great solution instead of 10 okay ones.

Choosing the public API

Let's say that you've established that you want to publish your package. You've pulled the relevant code from your application and put it in a separate folder. For your code to be eligible to be published on package.elm-lang.org you must make some changes to your elm.json file. You should see https://github.com/elm/compiler/blob/master/docs/elm.json/package.md for a detailed explanation and example of how it should look. One thing to note is the "exposed-modules" node. Here you whitelist which modules should be exposed to the public. This works the same way as you usually do inside a module: you specify which values should be available to the public.


When you've added the modules you want the end-user to access to the "exposed-modules" node you have to write some documentation. This is not just me urging you to write documentation, mind you. If you try to build your code without having written any form of documentation the compiler will actually stop you! It will tell you that all exposed modules should have some documentation stating its purpose and every exposed type, function and value must have a documentation comment.

Having to document every part of your public API might seem unnecessary at first, but think about how annoying it is to find a package that looks promising but has no documentation whatsoever. IMO you shouldn't be required to read the source code to figure out how to use it.

Another interesting part of the Elm package repository is that there is no quantitative information on how many stars, forks, likes, retweets or regrams a package has. The only way to "sell" your package is by having great documentation! You make people want to use your package because it has the best explanation of why it exists and what problem it solves and because your documentation is sprinkled with easy to understand usage examples.

https://package.elm-lang.org/help/documentation-format is a great write-up on Elm's documentation format and how to write good documentation.


Elm's ecosystem uses semantic versioning. Semantic versioning is defined by https://semver.org like this:

Given a version number MAJOR.MINOR.PATCH, increment the:

  1. MAJOR version when you make incompatible API changes,
  2. MINOR version when you add functionality in a backwards-compatible manner, and
  3. PATCH version when you make backwards-compatible bug fixes.

Many package ecosystems use this versioning scheme by convention, but in Elm it is actually enforced! To my knowledge, this is truly unique.

This is made possibly by the compiler. When you use the command elm bump to update your package's version number, Elm will compare the API of the currently published version with the one you have locally. If you have made breaking changes in the public API, Elm will automatically update the MAJOR version of your package. If you've added something to the public API without changing any of the currently exposed values, the MINOR version will be updated. If there aren't any changes in the public API at all, the PATCH version will be updated.

And that's not all. If you manually edit the version number in elm.json and try to publish, Elm will run the same checks. If you made a breaking change in the API but only updated the MINOR version, elm publish will prevent you from publishing it! This is pretty awesome, as it prevents any breaking changes from sneaking into MINOR or PATCH releases.


You have found the right problem to solve and validated the usefulness of your package. You have written the code. You have documented it well and published it to the official repository. Great job! Now go spread the word, listen to your users' feedback and iterate on it. Remember: software is never finished.

←Previous postNext post →