Skip to content


Switch branches/tags

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time

Idiomatic Elm Package Guide

Goals/Table of Contents

The purpose of this guide is to provide you with resources to get started writing an Elm package. And to help you write an Elm package that is:

  1. Valuable
  2. Constrained to prevent impossible states
  3. Easy to learn and use
  4. Easy to tell if it's the right fit for the problem at hand
  5. Consistent with the README and documentation conventions in the Elm community

How to Use This Guide

Check out this tweet that lays out some ideas from Elm's philosophy! It's got some great points regarding both community and API design.

You can read through for inspiration. It's a good starting point for your if you want to copy-paste it.

The rest of this document provides guiding principles, tips, and resources.

Feedback through Slack, Github issues, or pull requests is always welcome! If it's not an obvious change, it might be best to hold off on the pull request until after some initial discussion around the idea to make sure we're on the same page.

Learning Resources

The Basics

Here is a blog post about the process of publishing an Elm package:

The Basic Steps to Publish a Package in Elm 0.19 - Alex Korban

Core Principles

1. Valuable

If your package isn't valuable, then the rest of these principles won't help you much! Here are some tips to maximize the value of your Elm package.

  • Start simple. Introduce complexity sparingly.
  • Valuable doesn't mean comprehensive. It can be a minimal, simple package but still be extremely valuable. Think of the single-purpose philosophy of unix tools like ls or grep.
  • Design a consumer-driven API (see 49:41-52:57)
  • Check out Let's Publish Nice Packages - Brian Hicks at Elm Europe 2018 for some great tips like doing research on similar tools and avoiding direct ports from other libraries

Practice examples-Driven Development

When writing your Elm package, try to expose the minimal interface possible, AND drive that interface by concrete use cases. Test-driven development is a great way to do this on the micro level (see programming by intention). Take a look at the elm-test documentation for how to get started, and for best practices on writing a test suite.

On the macro level, try starting with an examples folder (i.e. examples-Driven Development). Start with a simple yet meaningful example. (For example, with elm-cli-options-parser, I started with an end-to-end example of building up the elm-test Command-Line Interface since it is a simple but meaningful and concrete interface). Then, add features to your package as needed to complete this simple but meaningful example and get it working fully end-to-end.

As you iterate on your design, review your examples folder and ask yourself some questions:

  • Are you proud to show these examples off?
  • Is it obvious to someone who hasn't used your library what they are doing?
  • Does the public API make sense?
  • Could the examples be any simpler if the API were different?
  • Is it discoverable (i.e. easy to find the functions you need to accomplish a task)?
  • Can you express things that are invalid using your API?

You can make sure that your examples are valid by adding a Travis job so you get emails if any of your checks fail. Some ways you can check your examples:

  • The elm-verify-examples tool lets you run the examples in your docs like unit tests!
  • Use elm make to make sure all of your examples compile
  • Have a good-old-fashioned elm-test suite that shows some meaningful use cases (avoid toy examples!)

2. Well-Constrained

When publishing a package you will need a toolkit of advanced Elm type techniques to create a clear public API, and one that models the constraints of your library's domain. The Official Elm API Design Guidelines are a good starting point.

Make use of advanced Elm types to make a simpler API and to model the constraints of your domain better

These articles by Charlie Koster on advanced Elm types are very useful when writing Elm packages.

These videos are full of great tips for designing APIs.

3. Easy to learn and use

Use the "Inverted Pyramid"

You need a hook that let's potential users know whether it's worth their time to read more about your package or try it out. So give very clear summaries at the top that include key points. You can use this basic inverted pyarmid structure from journalism (i.e. bottom line up front... however far you read, you've read the most important points).

  1. Key summary

    • Headline (the github project description... this is the first thing users see)
    • Why would I want to use this over other packages?
    • What problem does it solve?
  2. Important details

    • How do I install and use this library?
  3. Other background information

    • Advanced usage tips

Use Ubiquitous Domain Language

Use the same language everywhere, whether it's in a doc comment, the README, an example folder, an exposed function name or type, a type variable name (yes, even type variables, they show up in the docs, so they deserve great names, too!). And even your internal code! Bad naming in the internals of your code will inevitably leak out into confusing names that are public facing.

With that said, recognize that naming is a process. Don't expect to have the perfect names mapped out in your first commit. Iterate on the naming, just be sure to relentlessly do renaming refactors and module extracts as you see the opportunity for more clear names.

Learning Resources

See the Learning Resources section in the README template.

Here are some examples of learning sections from Elm package READMEs:

Maintain a file called in the root folder of your project on Github. The purpose of this is to make it easy for users to

  • Learn about new features (and how to use them)
  • Learn how to upgrade to new major versions
  • See when a bug is fixed

This is more granular than the commit log itself.

Copy-paste the template from Keep a Changelog to get started and follow the principles stated there. It's very well thought out and easy to follow once you get going with it.

Maintain a Frequently Asked Questions (FAQ)

Every time someone asks a question, consider answering it in your FAQ.

  • Keep FAQs in an file or FAQ section in your README.
  • Instead of directly answering a common question, send a link to the answer. That way you don't ever have to write that answer again, and it is there for future reference.
  • If a question keeps coming up, it may also mean that it's an opportunity to make your API simpler or more intuitive.

Always expose types that can be created from your API

You often see Github issues or pull requests like this one requesting that an Opaque Type be exposed in the API so that users of the API can annotate their functions that use values of that type. Avoid these types of requests by always following this rule of thumb:

If your public API allows you to create a value (even an intermediary one) of a given type, always expose that type in your public API so users can annotate their functions.

4. Easy to tell if it's the right fit for the problem at hand

Explicitly State Design Goals in Your README

What differentiates your project from any other project out there? Since Elm packages are reliable due to the nature of the elm language and its guarantees, what makes Elm packages stick out more is not its reliability, but its design philosophy. So we put the design philosophy as the first section after the initial introduction.

Writing out explicit design goals is a great idea even before you write any code (of course you can always revise them). They serve as:

  • A reminder to the package author of the core principles during design iteration
  • A clear statement of goals to help users decide whether the library is a good fit for them
  • A reference point for conversations about feature requests that helps ground the conversation in the basic goals of the library. This makes for a much more empathetic conversation (for example, someone could have a great idea that's not inline with the design goals of a library... in that case, perhaps a new library could be created, OR a different solution could be considered that honors the design goals of the library)

Here are some examples of design goals clearly stated in an Elm package README:

See the Design Goals section of the README template.

5. Consistent with the README and documentation conventions in the Elm community

You can use this template as a starting point. See the How to Use This Guide section of this README!

Here are some examples of packages that you can use as inspiration:

Put a Headline and Elm Package link in the Github Project description

If you click edit up at the top-right of your github page, you'll have a place to enter a Description and Website. Put a link to your project's Elm package page in the Website. In the Description, put a catchy headline that summarizes what your library does and what makes it unique in a short sentence.

For example, for mdgriffith/style-elements it is:

Description: Create styles that don't mysteriously break! Website:


The recommended license for Elm projects is BSD3.

Package Naming

  • The Elm community encourages that package authors follow its Literal Naming Policy.

  • The Elm core team recommends that you "use the elm- prefix unless elm already appears in the repository name".

Contributing Section or Document

If you create a file called CONTRIBUTING, Github will automatically link to it when your users create issues or pull requests. It's a great idea to store it in a separate file, but be sure to link to it!

Many package authors prefer to have discussions before they get pull requests. If that's the case for you, give a note in the ## Contributing section of your readme to clarify that.

Note that no matter how clear your contributing guidelines are, many pull requests and issues are created without noticing them. That's alright! Kindly link to the relevant guidelines to frame the conversation and make it as constructive as possible! I often like to frame feature requests in terms of the design goals of the library as well. This makes it less of a "who's right?" zero-sum game, and more of a collaborative discussion about "how aligned is this direction with these design goals?"

Thank Your Contributors!

Remember to keep a file or a section in your readme to list of contributors and recognize their work! I like to include both contributors of code (through pull requests) as well as those who share a lot of feedback or are very helpful reporting issues. Open source not just about one person's work, it's about community working together!


Everything you need to know to publish a useful, idiomatic Elm package!








No releases published

Sponsor this project



No packages published