ExDoc generates HTML, Markdown and EPUB, and the versions dropdown needs HexDocs
ExDoc produces HTML, EPUB, and Markdown documentation for Erlang and Elixir projects
At a glance
- What is it?
- elixir-lang/ex_doc turns Erlang and Elixir API documentation into offline HTML, Markdown and EPUB, and it is the tool behind the official Elixir documentation. Some of its most visible features, including cross-project go-to and version switching, only work when the docs are hosted on HexDocs.
- Who is it for?
- Use ExDoc if your project is an Elixir or Erlang library, since it is the documentation generator the ecosystem expects and the format HexDocs serves. Do not expect the hosted features, cross-package navigation and version switching, to work on your own server without HexDocs.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- 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 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Mix, Rebar or the escript, with a real difference between them
ExDoc offers three entry points and they are not equivalent.
Mix is the recommended path for Elixir projects and the best documented. It requires Elixir v1.15 or later, and the dependency is added the usual way with a dev-only, non-runtime spec:
def deps do
[
{:ex_doc, "~> 0.34", only: :dev, runtime: false, warn_if_outdated: true},
]
endThe `warn_if_outdated` flag is worth noting because it is the difference between a project whose documentation silently ages and one that tells you when a newer ExDoc exists. `runtime: false` keeps the generator out of your releases, which is what you want from a documentation tool.
Rebar is the recommended path for Erlang projects. From Erlang/OTP 24 onward, ExDoc can render documentation written with EDoc, and the implementation is a separate project, rebar3_ex_doc, which the README links rather than describing. If you are on Erlang and reading the README looking for Mix instructions, that is the wrong branch.
The CLI is the escript, which is the option when you have no Mix project to hang it from. It is installed globally with `mix escript.install hex ex_doc`, then invoked against a compiled project:
ex_doc "PROJECT_NAME" "PROJECT_VERSION" _build/dev/lib/project/ebin -m "PROJECT_MODULE" -u "https://github.com/GITHUB_USER/GITHUB_REPO" -l path/to/logo.pngYou have to supply the name, the version, the ebin directory and the main module by hand, because there is no project file to read them from. For umbrella projects you can pass several ebin directories, in which case modules are grouped by application by default, and the README notes that this can be overridden with a `groups_per_modules` option. A config file can be supplied with `--config` in either Elixir or Erlang format.
That difference in effort is the real distinction between the three paths. Mix reads your project metadata automatically; the escript makes you supply everything.
The hosted features are the ones that make ExDoc feel complete
Reading the feature list closely, a meaningful number of ExDoc's best behaviour depends on where the documentation is hosted.
When hosted, ExDoc relies on the browser's page transitions for better UX, caching and enhanced accessibility. That is a deliberate architectural choice rather than an incidental benefit: it is why the generated site behaves like an application rather than a set of HTML files, and why it does not degrade as well when opened directly from disk.
The version dropdown and the go-to-latest notifications are configured automatically when hosted on HexDocs. That is the clearest example. A version switcher is exactly the feature you want for a library, and it is tied to the publishing platform rather than to the generated files.
The go-to shortcut with autocompletion takes the reader to any HexDocs package documentation, which is a documentation-wide navigation feature rather than a property of your project.
The rest work anywhere. Full-text search. Quick search with autocompletion on the `s` key. Keyboard shortcuts with `?` showing the help. Tooltips for links to modules and functions, both within your project and to other projects. Night mode following the browser preference. Responsive design covering phones and tablets. A direct source-code link for every documented entity. A customisable logo and favicon.
So the practical picture is: the search, the tooltips, the source links and the extras system are yours; the version switching and cross-package navigation belong to HexDocs. Generating with ExDoc and serving it yourself gives you a good documentation site, not a HexDocs clone.
One more capability is easy to miss in the list. Alongside HTML, ExDoc generates Markdown output including `llms.txt`, and EPUB. That is the output side of the tool rather than the UI, and it is a separate reason to care about it if your readers are agents rather than browsers.
Extras change meaning with their file extension
The `:extras` option is where most of the interesting configuration lives, and the extension is not cosmetic.
Markdown with the `.md` extension is for general long-term text, which in practice means your README and your licence.
Cheatsheets use `.cheatmd`, and the README characterises them as useful for discovery and quick reference, with a link to the cheatsheet documentation.
Livebooks use `.livemd` and are for tutorials, interactive examples and deep dives, running on Livebook.
The three are different documents aimed at different moments, and picking the extension is how you say which moment you mean. A tutorial someone will follow step by step and a reference table someone will scan are the same words read in completely different ways, and this is the mechanism that separates them.
The configuration is short:
extras: ["README.md", "LICENSE", "tutorial.livemd", "cheatsheet.cheatmd"]with the Erlang form given as `{extras, [<<"README.md">>, <<"cheatsheet.cheatmd">>]}`. Full configuration detail lives behind `mix help docs`, which the README points to rather than duplicating.
The other configuration keys in the same file are the ones you will notice immediately when they are missing. `main` sets the entry page and can be changed to a module name instead of `"readme"`. `logo` points at an image. ExDoc pulls in the application name and version on its own, but the README says you may want to set `:name`, `:source_url` and `:homepage_url` in order to have nicer output, and those are the keys behind the source links and the title.
Metadata across two languages, and one missing dev package
Metadata keys are supported in both ecosystems, and the syntax differs enough to trip people up.
In Elixir you add them as annotation arguments. For a module, `@moduledoc` applies the annotation to everything inside it, which includes functions, macros, callbacks and types:
@moduledoc since: "1.10.0"For a function, `@doc` does the same at that granularity, so `@doc since: "1.13.1"` marks a single function as available since that version.
In Erlang's EDoc the equivalent is a comment annotation, `%% @since 0.1.0`, which is a different shape from Elixir's key-value annotation because EDoc is comment-driven rather than attribute-driven.
That `since` metadata is what makes the version dropdown useful, and it is worth the effort to fill in. A library that does not mark when things appeared can only tell you which release of your own library you are reading.
Syntax highlighting comes from the separate makeup project, with Erlang and Elixir highlighters included by default. Other languages are added by depending on the corresponding `makeup_LANGUAGE` package, for HTML that is `{:makeup_html, ">= 0.0.0", only: :dev, runtime: false}` in Mix and `{makeup_html, "0.1.1"}` in Rebar3.
The one genuine installation trap in the README is an Erlang packaging issue rather than an ExDoc issue. Some distributions split Erlang into multiple packages, and at least one ExDoc dependency, `earmark_parser`, requires the Erlang development environment. The symptom is a message about a missing `parsetools-2.3.1/include/yeccpre.hrl`. On Debian and its derivatives the fix is `apt install erlang-dev`.
It is a good example of a build failure whose error message points nowhere near the cause.
Where ExDoc sits against the alternatives
The comparison worth making is not with other documentation generators in other ecosystems, but with what an Elixir project does without ExDoc.
Against hosting on HexDocs, the difference is the publishing model rather than the generation. When hosted on HexDocs, ExDoc automatically configures the version dropdown, go-to-latest notifications and navigation to HexDocs package documentation.
The decision is therefore whether your documentation needs to be discoverable as part of a package ecosystem. A library that others depend on benefits from the HexDocs layer more than it suffers from it. An internal application, or a library you do not publish, gets more from self-hosting and loses nothing important.
One thing ExDoc deliberately does not do is run code. It reads documentation already written in your source, so the cost of adopting it is the cost of writing `@doc` and `@moduledoc` strings, and no tool can reduce that. A project with sparse documentation will get a sparse ExDoc site, cleanly formatted and empty.
The licence is a custom one GitHub cannot classify, with the terms in the `LICENSE` file at the root. For a tool most teams use as a dev dependency, read that file rather than assuming, since documentation generators are occasionally the thing a hosted vendor wants a different arrangement for.
Editorial conclusion
Use ExDoc if your project is an Elixir or Erlang library, since it is the documentation generator the ecosystem expects and the format HexDocs serves. Do not expect the hosted features, cross-package navigation and version switching, to work on your own server without HexDocs. Verify first that you are on Elixir 1.15 or later, since that is the stated Mix requirement, that on Debian or a derivative you have installed `erlang-dev` if a dependency such as `earmark_parser` fails to build, and that your `:extras` list uses the extensions you think it does, because the meaning of a page in the output changes with the extension.
Frequently asked questions
How do I add ExDoc to an Elixir project?
Add `{:ex_doc, "~> 0.34", only: :dev, runtime: false, warn_if_outdated: true}` to your deps, run `mix deps.get`, and then `mix docs`. ExDoc requires Elixir v1.15 or later.
How do I use ExDoc for an Erlang project?
From Erlang/OTP 24 onward you can render EDoc documentation with ExDoc through the separate rebar3_ex_doc project, which the README links. Rebar is the recommended path for Erlang, and for Elixir projects Mix is recommended.
What file formats can I add to my documentation?
Markdown with the `.md` extension for general long-term text, cheatsheets with `.cheatmd` for quick reference, and livebooks with `.livemd` for tutorials and interactive examples. They go in the `:extras` option.
Why does my Erlang build fail with a missing yeccpre.hrl?
Some distributions split Erlang into packages, and the ExDoc dependency `earmark_parser` needs the Erlang development environment. On Debian and its derivatives the fix is `apt install erlang-dev`.
Do ExDoc's version dropdown and cross-package links work on my own server?
Not fully. The version dropdown and go-to-latest notifications are configured automatically when hosted on HexDocs, and the `g` shortcut navigates to any HexDocs package. Search, quick search, tooltips and the extras system work wherever you serve the output.
How do I mark when a function was introduced?
In Elixir, annotate `@doc since: "1.13.1"` for a function or `@moduledoc since: "1.10.0"` for a module, which applies to everything inside it. In Erlang's EDoc the equivalent comment annotation is `%% @since 0.1.0`.
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/elixir-lang-ex-doc)