Skip to content
Back to skills

Exdoc Config

ASecurity

Configures ExDoc for Elixir projects including mix.exs setup, extras, groups, cheatsheets, and livebooks. Use when setting up or modifying ExDoc documentation generation.

  • 79 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added May 27, 2026
developmentgobashsqlgitapidocumentation

Works with

  • api

Security analysis

A100/100

Pro scans all 3 files and shows the line behind each finding

Scanned May 27, 2026

npx -y skills add existential-birds/beagle --skill exdoc-config --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Exdoc Config?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Exdoc Config
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/existential-birds-exdoc-config/badge)](https://www.skillsdirectory.com/skills/existential-birds-exdoc-config)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: exdoc-config
description: Configures ExDoc for Elixir projects including mix.exs setup, extras, groups, cheatsheets, and livebooks. Use when setting up or modifying ExDoc documentation generation.
---

# ExDoc Configuration

## Quick Reference

| Topic | Reference |
|-------|-----------|
| Markdown, cheatsheets (.cheatmd), livebooks (.livemd) | [references/extras-formats.md](references/extras-formats.md) |
| Custom head/body tags, syntax highlighting, nesting, annotations | [references/advanced-config.md](references/advanced-config.md) |

## Gates

Use this sequence before claiming ExDoc is wired correctly or that docs build:

1. **Dependencies resolved** — Run `mix deps.get` from the project root. **Pass:** exit code `0`, and `mix.exs` includes `ex_doc` as in [Dependency Setup](#dependency-setup) (or the project’s equivalent dev-only docs dep).
2. **Extra paths real** — For every path string in `extras/0` (and in `groups_for_extras/0` if used), confirm that path exists in the repo **or** you have just created that file. **Pass:** no stale or typo paths remain when you run `mix docs`.
3. **Docs build** — Run `mix docs`. **Pass:** exit code `0`, and the HTML entry exists at `<output>/index.html` (default `<project>/doc/index.html`; use `docs: [output: ...]` if you changed `output`).

For cheatsheets, livebooks, or custom head/body assets, follow the same “path exists before listing” rule; see [When to Load References](#when-to-load-references).

## Dependency Setup

Add ExDoc to `mix.exs` deps:

```elixir
defp deps do
  [
    {:ex_doc, "~> 0.34", only: :dev, runtime: false}
  ]
end
```

## Project Configuration

Configure your `project/0` function in `mix.exs`:

```elixir
def project do
  [
    app: :weather_station,
    version: "0.1.0",
    elixir: "~> 1.17",
    start_permanent: Mix.env() == :prod,
    deps: deps(),

    # ExDoc
    name: "WeatherStation",
    source_url: "https://github.com/acme/weather_station",
    homepage_url: "https://acme.github.io/weather_station",
    docs: docs()
  ]
end
```

## The docs/0 Function

Define a private `docs/0` function to keep project config clean:

```elixir
defp docs do
  [
    main: "readme",
    logo: "priv/static/images/logo.png",
    output: "doc",
    formatters: ["html", "epub"],
    source_ref: "v#{@version}",
    extras: extras(),
    groups_for_modules: groups_for_modules(),
    groups_for_extras: groups_for_extras()
  ]
end
```

### Key Options

| Option | Default | Description |
|--------|---------|-------------|
| `main` | `"api-reference"` | Landing page module name or extra filename (without extension) |
| `logo` | `nil` | Path to logo image displayed in sidebar |
| `output` | `"doc"` | Output directory for generated docs |
| `formatters` | `["html"]` | List of output formats (`"html"`, `"epub"`) |
| `source_ref` | `"main"` | Git ref used for "View Source" links |
| `assets` | `nil` | Map of source directory to target directory for static assets |
| `deps` | `[]` | Links to dependency documentation |

### Setting the Landing Page

The `main` option controls what users see first:

```elixir
# Use the README as the landing page (most common)
docs: [main: "readme"]

# Use a specific module as the landing page
docs: [main: "WeatherStation"]

# Use a custom guide
docs: [main: "getting-started"]
```

The value matches the extra filename without its extension, or a module name.

## Extras

Extras are additional pages beyond the API reference. Add them as a list of file paths:

```elixir
defp extras do
  [
    "README.md",
    "CHANGELOG.md",
    "LICENSE.md",
    "guides/getting-started.md",
    "guides/configuration.md",
    "guides/deployment.md",
    "cheatsheets/query-syntax.cheatmd",
    "notebooks/data-pipeline.livemd"
  ]
end
```

### Controlling Extra Titles

By default, ExDoc uses the first `h1` heading as the title. Override with a keyword tuple:

```elixir
defp extras do
  [
    {"README.md", [title: "Overview"]},
    {"CHANGELOG.md", [title: "Changelog"]},
    "guides/getting-started.md"
  ]
end
```

### Ordering

Extras appear in the sidebar in the order listed. Put the most important pages first:

```elixir
defp extras do
  [
    "README.md",
    "guides/getting-started.md",
    "guides/architecture.md",
    "guides/deployment.md",
    "CHANGELOG.md"
  ]
end
```

## Grouping

### Grouping Modules

Organize modules into logical sections in the sidebar:

```elixir
defp groups_for_modules do
  [
    "Sensors": [
      WeatherStation.Sensor,
      WeatherStation.Sensor.Temperature,
      WeatherStation.Sensor.Humidity,
      WeatherStation.Sensor.Pressure
    ],
    "Data Processing": [
      WeatherStation.Pipeline,
      WeatherStation.Pipeline.Transform,
      WeatherStation.Pipeline.Aggregate
    ],
    "Storage": [
      WeatherStation.Repo,
      WeatherStation.Schema.Reading,
      WeatherStation.Schema.Station
    ]
  ]
end
```

Use regex to group by pattern:

```elixir
defp groups_for_modules do
  [
    "Sensors": [~r/Sensor/],
    "Schemas": [~r/Schema/],
    "Pipeline": [~r/Pipeline/]
  ]
end
```

Modules not matching any group appear under a default "Modules" heading.

### Grouping Functions

Group functions within a module using `groups_for_docs`:

```elixir
defp docs do
  [
    groups_for_docs: [
      "Lifecycle": &(&1[:section] == :lifecycle),
      "Queries": &(&1[:section] == :queries),
      "Mutations": &(&1[:section] == :mutations)
    ]
  ]
end
```

Tag functions in your module with `@doc` metadata:

```elixir
@doc section: :lifecycle
def start_link(opts), do: GenServer.start_link(__MODULE__, opts)

@doc section: :queries
def get_reading(station_id), do: Repo.get(Reading, station_id)
```

### Grouping Extras

Organize guides, cheatsheets, and notebooks in the sidebar:

```elixir
defp groups_for_extras do
  [
    "Guides": [
      "guides/getting-started.md",
      "guides/configuration.md",
      "guides/deployment.md"
    ],
    "Cheatsheets": [
      "cheatsheets/query-syntax.cheatmd",
      "cheatsheets/ecto-types.cheatmd"
    ],
    "Tutorials": [
      "notebooks/data-pipeline.livemd",
      "notebooks/sensor-setup.livemd"
    ]
  ]
end
```

Use glob patterns for convenience:

```elixir
defp groups_for_extras do
  [
    "Guides": ~r/guides\/.*/,
    "Cheatsheets": ~r/cheatsheets\/.*/,
    "Tutorials": ~r/notebooks\/.*/
  ]
end
```

## Dependency Doc Links

Link to documentation for your dependencies so ExDoc cross-references resolve:

```elixir
defp docs do
  [
    deps: [
      ecto: "https://hexdocs.pm/ecto",
      phoenix: "https://hexdocs.pm/phoenix",
      plug: "https://hexdocs.pm/plug"
    ]
  ]
end
```

This enables references like `t:Ecto.Schema.t/0` to link directly to the dependency docs.

## Generating Docs

```bash
# Generate HTML docs
mix docs

# Open in browser
open doc/index.html
```

## Complete mix.exs Example

```elixir
defmodule WeatherStation.MixProject do
  use Mix.Project

  @version "1.3.0"
  @source_url "https://github.com/acme/weather_station"

  def project do
    [
      app: :weather_station,
      version: @version,
      elixir: "~> 1.17",
      start_permanent: Mix.env() == :prod,
      deps: deps(),
      name: "WeatherStation",
      source_url: @source_url,
      homepage_url: "https://acme.github.io/weather_station",
      docs: docs()
    ]
  end

  defp docs do
    [
      main: "readme",
      logo: "priv/static/images/logo.png",
      source_ref: "v#{@version}",
      formatters: ["html"],
      extras: extras(),
      groups_for_modules: groups_for_modules(),
      groups_for_extras: groups_for_extras(),
      deps: [
        ecto: "https://hexdocs.pm/ecto",
        phoenix: "https://hexdocs.pm/phoenix"
      ]
    ]
  end

  defp extras do
    [
      "README.md",
      "CHANGELOG.md",
      "guides/getting-started.md",
      "guides/configuration.md",
      "guides/deployment.md",
      "cheatsheets/query-syntax.cheatmd",
      "notebooks/data-pipeline.livemd"
    ]
  end

  defp groups_for_modules do
    [
      "Sensors": [~r/Sensor/],
      "Data Processing": [~r/Pipeline/],
      "Storage": [~r/Schema|Repo/]
    ]
  end

  defp groups_for_extras do
    [
      "Guides": ~r/guides\/.*/,
      "Cheatsheets": ~r/cheatsheets\/.*/,
      "Tutorials": ~r/notebooks\/.*/
    ]
  end

  defp deps do
    [
      {:phoenix, "~> 1.7"},
      {:ecto_sql, "~> 3.12"},
      {:ex_doc, "~> 0.34", only: :dev, runtime: false}
    ]
  end
end
```

## When to Load References

- Setting up cheatsheets or livebooks as extras -> extras-formats.md
- Injecting custom CSS/JS, configuring syntax highlighting, or tuning module nesting -> advanced-config.md

Files in this skill

  • SKILL.md8.4 KB
  • references/advanced-config.md6.6 KB
  • references/extras-formats.md6.5 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.