When you are developer and work on different projects, sooner or later you would face a need to extract some part of functionality into separate libraries to reuse it.

Different languages and frameworks provide their own functionality to distribute libraries among other developers or within a single company.

You probably already know some of them. “npm” is a package manager for JavaScript. For Ruby, it would be “Ruby Gems”. Elixir is not an exception here. For Elixir and Erlang, we have “Hex” as a package manager.

So, let’s see how we can publish our own Elixir package.

To publish a package we need to have one. In my example, I would use a package called “Stash Exchange” which I’ve just created.

It has a single function exchange/1. You pass a value into that function to store it. The function returns the previously stored value and updates the storage with the new value.

Here you can see an implementation of that function:

@initial_state 1
@stash_name __MODULE__

def exchange(value) do
  if is_nil(Process.whereis(@stash_name)) do
    Agent.start(fn -> @initial_state end, name: @stash_name)
  end

  Agent.get_and_update(@stash_name, fn state -> {state, value} end)
end

Now let’s try to publish that package.

Register a new Hex user

In order to publish packages to Hex, we need to have an account there. If you already have one, then you can run mix hex.user auth from your terminal window to authenticate.

If you are new to Hex then you can register either by using web form (https://hex.pm/signup) or using the command line by calling mix hex.user register and follow the instructions.

Configure the project metadata

Before we publish a package to Hex we need to provide some required attributes such as name, description, list of licenses etc.

Before you pick the name for your package, make sure the name is available. You can either review list of packages or search by the name you have already in mind.

There are some attributes I’ve added for Stash Exchange package. First, in the project attributes we need to have a description and optional source code URL. We also need to describe package attribute with extended information. In my case, that’s name, licenses, maintainers and links.

def project do
  [
    # ...
    description: "The single value storage",
    source_url: github_link(),
    package: package()
  ]
end

defp package() do
  [
    name: "stash_exchange", # Optional if we want to keep OTP app name
    maintainers: ["Vitali Tatarintev"],
    licenses: ["MIT"],
    links: %{"GitHub" => github_link()}
  ]
end

defp github_link() do
  "https://github.com/ck3g/stash_exchange"
end

You can always refer to mix help hex.publish to get the list of available attributes.

Publishing and documentation

Once our metadata is ready we are ready to publish the package.

Packages are being published by using mix hex.publish.

The Hex tool will also generate documentation for the package by calling mix docs. ExDoc package provides that command, so it would be nice to have it as a dependency for the publishable package. You are free to use any other library to generate docs. The documentation will be published on hexdocs.

Check out Writing documentation in Elixir to learn more about writing and generating docs.

You can also publish or update the package without documentation or even update only documentation by calling mix hex.publish package or mix hex.publish docs accordingly.

The mix help hex.publish command helps to remember those options as well as others.

Now, after we have cleared up the things around documentation we are ready to publish the package.

→ mix hex.publish
Publishing stash_exchange 0.1.0
  App: stash_exchange
  Name: stash_exchange
  Files:
    lib/stash_exchange.ex
    mix.exs
    README.md
    LICENSE.md
  Description: The single value storage
  Version: 0.1.0
  Build tools: mix
  Licenses: MIT
  Maintainers: Vitali Tatarintev
  Links:
    GitHub: https://github.com/ck3g/stash_exchange
  Elixir: ~> 1.6
Before publishing, please read the Code of Conduct: https://hex.pm/policies/codeofconduct
Proceed? [Yn] Y
Building docs...
Docs successfully generated.
View them at "doc/index.html".
Passphrase:
Publishing package...
[#########################] 100%
Package published to https://hex.pm/packages/stash_exchange/0.1.0 (2472ac58ec48ce1a8d720a508a9d4d14c9a6a46e22988c5b92437dcae4d0b63b)
Publishing docs...
[#########################] 100%
Docs published to https://hexdocs.pm/stash_exchange/0.1.0

The passphrase is actually your password. It was not obvious for me for the first time. Also, the publish command didn’t work for me in a separate terminal window. You might need to run mix hex.user auth to re-authenticate yourself.

That is it. The package has been published and we can navigate to the package page to check it out. In my case, that’s a https://hex.pm/packages/stash_exchange/0.1.0 page.

Use the package as a dependency

The package was published and we can start using it.

Let’s create a simple Elixir app, install that package as a dependency and try it out.

→ mix new stash_exchange_proxy

First, we need to add it as a dependency in the mix.ex file:

defp deps do
  [{:stash_exchange, "~> 0.1.0"}]
end

Then we define a simple proxy function to call the StashExchange.exchange/1 function:

defmodule StashExchangeProxy do
  def exchange(value) do
    StashExchange.exchange(value)
  end
end

Now we need to install dependencies

→ mix deps.get

That is it. We are ready to play with that function in the Interactive Elixir session.

iex> StashExchangeProxy.exchange("Elixir")
1

iex> StashExchangeProxy.exchange(%{awesome: true})
"Elixir"

iex> StashExchangeProxy.exchange("?")
%{awesome: true}

It seems to be working.

Wrapping up

We’ve just published our first Elixir package. As we can see that is extremely easy to do. Elixir and Hex provide us with all required tools to do that.

Now it is your turn. Do you have the functionality you would like to share between your projects? You can extract it and publish as a separate package.

Even if you don’t want to make your packages public. Hex allows publishing private packages as well. Check out “Private packages” page to learn more.