hexpm, the Phoenix application behind the Hex package registry
API server and website for Hex
At a glance
- What is it?
- hexpm is the Elixir and Phoenix application that serves hex.pm, the package registry and API for the Erlang ecosystem. It is not something most developers install, but it is the piece that makes hex publish, resolve and serve packages, and its README is a description of how to run a full instance locally.
- Who is it for?
- hexpm suits a contributor who wants to work on the Hex infrastructure itself, since the README documents a complete local setup with PostgreSQL, sample data and a running server on port 4000, and it suits anyone who needs to run a private or experimental instance of the registry.
- Can I use it commercially?
- Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly Elixir, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What runs on hex.pm, and what this repository is
hexpm is the API server and website for hex.pm. That is the whole scope, and it is worth being precise about the division of labour, because the name overlaps with a package you have probably used.
The client is a separate repository, hex, which is the package manager for the Erlang ecosystem and the thing that Mix talks to. hexpm is the server side of the same system: the registry that stores package metadata and releases, the API that the client calls, and the web frontend that renders hex.pm.
The README makes the relationship concrete in a way that explains the project's test strategy. The client uses hexpm for integration tests, so hexpm needs to support all the versions the client supports, and CI ensures that tests are run on all supported versions. That is a strong coupling between two repositories, and it is the reason the version compatibility of the server is not something a maintainer can pick in isolation.
The implementation is Elixir on Phoenix, with a PostgreSQL backend. The repository layout follows the standard Phoenix shape: a lib/ directory for the application code, config/ for the environment configuration, priv/ for the repository and the Ecto migrations, test/ for the test suite, rel/ for the release configuration, and assets/ for the frontend. There is a mix.exs and a mix.lock, a Dockerfile, a docker-compose.yaml, and a.credo.exs for Credo, the Elixir static analysis tool, plus a.formatter.exs and a.envrc.
The last push was on 2026-10-19 and the repository has no GitHub releases, so there is no tag series to pin against. The homepage is hex.pm, and the README's license section carries an Apache License 2.0 notice with a copyright line for Six Colors AB dated 2015, which is the company behind Hex.
Setting up a local instance, which is a PostgreSQL exercise
The contributing section of the README is a setup guide, and it starts with the database because that is where the friction is.
The sequence is three steps. Run mix setup to install dependencies, create and seed the database. Run mix test. Then run iex -S mix phx.server and visit http://localhost:4000/. The setup alias is defined in mix.exs, and the README points to it and to the sections below for more information.
The PostgreSQL requirements are specific. The version should be 9.4 or newer, because Hexpm uses the jsonb type. Two modules must be available, pg_trgm for trigram search and pgcrypto for the cryptographic functions, and both live in the postgresql-contrib package, whose name varies by operating system. If the modules are missing, the Ecto migrations will fail, and that failure is about the module rather than about the migration.
For the database itself there are two options. By default Hexpm connects to a localhost PostgreSQL database named hexpm_dev with the username postgres and the password postgres. The compose file is the quicker way to get that:
docker-compose up -d dbThat service runs postgres:14 with the same credentials, a named volume pg-data mounted at /var/lib/postgresql/data, and port 5432 published to the host. Once the database is up, the migrations and the seed data are Mix tasks:
mix do ecto.create + ecto.migrate
mix run priv/repo/seeds.exsThe first creates the database and runs the migrations, the second seeds the local instance with sample data so you have something to look at.
One development detail is easy to miss. Development object storage is shared across worktrees under the operating system's temporary directory, and HEXPM_LOCAL_STORE_DIR is the variable to set if you want a different shared location. That matters if you work on more than one branch at a time and find uploaded files missing from a second worktree.
The frontend build is a separate toolchain
Phoenix projects that serve a web frontend usually need a JavaScript build, and Hexpm's is Node and Yarn based.
The README recommends enabling Corepack for a better developer experience, which is a single command:
corepack enableThen the asset dependencies are installed from inside the assets directory:
cd assets && yarn installAnd if you do not have Yarn, npm install in the same directory works too.
The Dockerfile shows how this fits into a release build, and it does a few things worth copying. The build stage is based on a pinned hexpm/elixir image with specific Elixir and Erlang versions, and it installs git, build-essential and ca-certificates. Mix local.hex and mix local.rebar are run with --force so the build does not prompt. The build environment is MIX_ENV=prod.
The dependency compilation step is the interesting one. It computes a partition count from nproc, halves it, and clamps it between 1 and 4, then sets MIX_OS_DEPS_COMPILE_PARTITION_COUNT before running mix deps.compile. The comment links to the Mix documentation for compiling dependencies across multiple OS processes, and the effect is that dependencies compile in parallel, which is the difference between a slow build and a tolerable one on a large dependency tree.
The Dockerfile also separates the config copy from the source copy on purpose. The comment says runtime.exs is only read by the release, so it is copied in right before it, and a change to it does not recompile the dependencies. That is a caching decision, and it means a runtime configuration change is a cheap rebuild rather than a full dependency compile.
For assets the build runs mix assets.deploy, then mix compile, and the compiled output is what the runtime stage ships.
IP geolocation for the audit log, and the two implementations
The dashboard audit log at /dashboard/audit-logs shows the country of each entry's IP address, and the way that is implemented is a good example of a dependency that behaves differently in development and production.
In dev and test, the implementation is Hexpm.Geo.Local, and it needs no database at all. It resolves addresses from a map called :geo_local_lookups in config/dev.exs, where localhost is mapped by default, and you add entries there to exercise other countries in a test. That is a deliberate design, since a test suite should not depend on a downloaded geolocation file or on network access to determine what a page renders.
In production, the implementation is Hexpm.Geo.Geolix, which reads an MMDB IP-to-country database through the geolix package. The database used is the free DB-IP IP-to-Country Lite file, licensed CC BY 4.0, and any MaxMind-compatible MMDB also works. The attribution requirement is noted: it is rendered on the page.
The deployment story is where this gets interesting. With Docker there is nothing to do, because the image fetches the database at build time and bakes it into the release, and the application finds it automatically, so geolocation works out of the box. Each image build re-fetches the current file, and since DB-IP refreshes monthly, routine rebuilds keep it reasonably fresh. The Dockerfile comment adds that the build fails if the download fails, with no silent fallback to a missing file, and that the task retries with the previous month if the current month's file has not been published yet.
For other deployments, or a custom location, you download it and point Hexpm at the file:
mix download_geoip # -> priv/geoip/country.mmdb
export HEXPM_GEOIP_COUNTRY_PATH=priv/geoip/country.mmdbRe-running the task and restarting, or calling Geolix.reload_databases/0, updates it. The behaviour is fail-soft: if no database is found the application boots normally and the audit log locations are simply omitted until one is provisioned, and HEXPM_GEOIP_COUNTRY_PATH overrides the baked-in default.
Billing integration tests, and why they are excluded
The payment path is tested against a separate service, and the README is explicit that these tests are not part of a normal test run.
The chain is hexpm to hexpm_billing to Stripe, and the integration tests exercise it end to end. They are excluded from regular mix test runs and require additional setup, which is a sensible boundary: a payment test needs a Stripe sandbox, a running billing service, a webhook forwarder and a browser driver.
The setup has four moving parts. You create a Stripe sandbox from the dashboard by switching the account picker to sandbox and creating one, giving it a name such as hexpm-dev. You install and authenticate the Stripe CLI, and the README shows the commands:
brew install stripe/stripe-cli/stripe
stripe loginThat opens a browser to select which sandbox to log into, and the CLI generates restricted keys valid for 90 days stored in ~/.config/stripe/config.toml. The keys then go into hexpm_billing/config/dev.exs, with stripe_secret_key set to the sandbox secret key and stripe_publishable_key to the publishable key. Webhooks are forwarded with stripe listen --forward-to localhost:4001/webhooks/payments, which prints a signing secret beginning with whsec_ that you put in stripe_signing_secret_key, and that secret stays the same between CLI restarts.
The prerequisites are the billing service itself running on port 4001, which takes its own mix deps.get, mix ecto.setup and MIX_ENV=dev mix phx.server in that repository, and ChromeDriver for the browser tests, installed with brew install chromedriver.
Then the tests run, either all of them or a subset:
mix test --only integration
mix test test/hexpm_web/integration/sca_test.exs --include integrationThe second form is the one to reach for when you are working on the strong customer authentication flow specifically, and it needs the browser driver rather than just the CLI.
Editorial conclusion
hexpm suits a contributor who wants to work on the Hex infrastructure itself, since the README documents a complete local setup with PostgreSQL, sample data and a running server on port 4000, and it suits anyone who needs to run a private or experimental instance of the registry. It is the wrong tool if you want to install packages, because the client is the hex repository rather than this one, and it is the wrong choice if your goal is a general artifact registry, because the data model is built around Elixir and Erlang package metadata. Before contributing, note the version coupling the README calls out, since the hex client uses hexpm for its integration tests and hexpm must therefore support every client version the client supports, and check that PostgreSQL has the pg_trgm and pgcrypto modules available before the Ecto migrations will run.
Frequently asked questions
What is hexpm and how does it relate to Hex?
hexpm is the API server and website for hex.pm, written in Elixir with Phoenix. The package manager client lives in the separate hex repository, and the README notes the client uses hexpm for integration tests, so hexpm must support all the versions the client supports.
How do I set up hexpm locally?
Run mix setup to install dependencies, create and seed the database, then mix test, then iex -S mix phx.server and visit http://localhost:4000/. The database is PostgreSQL 9.4 or newer with the pg_trgm and pgcrypto modules available, and the compose file brings up a postgres:14 service with docker-compose up -d db.
How does hexpm resolve IP addresses to countries?
The audit log uses the :geo_impl setting. Development and test use Hexpm.Geo.Local, which reads a :geo_local_lookups map in config/dev.exs and needs no database, while production uses Hexpm.Geo.Geolix with an MMDB file, by default the DB-IP IP-to-Country Lite database.
How do I run the billing integration tests?
They need a Stripe sandbox, the Stripe CLI, a hexpm_billing instance on port 4001 and ChromeDriver, and they are excluded from a regular mix test run. The commands are mix test --only integration for all of them, or mix test test/hexpm_web/integration/sca_test.exs --include integration for the browser SCA tests alone.
What licence is hexpm released under?
The README carries an Apache License 2.0 notice with a copyright line for Six Colors AB dated 2015. The repository's own licence metadata is not classified, so the README section is the authoritative statement.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/hexpm-hexpm)Was this useful?