Cljdoc offers a centralized hosted library of docs which:
-
Are easy to publish
-
Automatically stay up to date
-
Are discoverable by users
-
And look good!
If you publish your library to Clojars, its docs should already be available (or available to build) on cljdoc.org.
Default handling:
-
API automatically documented
-
Articles include
README
,CHANGELOG
and articles underdoc/
(elsedocs/
), see auto-discovered articles
Note
|
Cljdoc currently only processes libraries that have been deployed to clojars. We do have ideas for processing source-based libraries, but have not implemented yet. |
When cljdoc is triggered to build your library’s documentation, it:
-
Downloads your library’s release jar from Clojars
-
Analyzes your library’s sources on git
-
Analyzes your library’s jar to discover its public API.
After building your docs, they are available at cljdoc.org for online and offline browsing.
See also: System Overview.
Cljdoc supports two markup formats:
-
Markdown for API docstrings and
.md
articles-
We use flexmark-java to render a GitHub flavored CommonMark dialect.
-
-
AsciiDoc for
.adoc
articles-
We use AsciidoctorJ to render AsciiDoc.
-
-
Plaintext for
.txt
articles and optionally docstrings-
Plaintext support was added for older projects, we recommend using minimal Markdown for docstrings and either Markdown or Asciidoc for your articles.
-
Important
|
The following examples use |
-
Badge URL:
https://cljdoc.org/badge/metosin/malli
-
Docs homepage URL:
https://cljdoc.org/d/metosin/malli
Expressed in Markdown:
[![cljdoc badge](https://cljdoc.org/badge/metosin/malli)](https://cljdoc.org/d/metosin/malli)
and AsciiDoc:
https://cljdoc.org/d/metosin/malli[image:https://cljdoc.org/badge/metosin/malli[cljdoc badge]]
Cljdoc starts with the release jar downloaded from Clojars.
A jar is associated with its specific git revision of sources via the <scm>
entry in the jar’s pom
.
This allows cljdoc to consult git hosted:
-
cljdoc config - options on how cljdoc should process your docs
-
articles - to include and present as part of your docs
-
sources files - to allows cljdoc to intelligently link back to articles, API source code, and your git repo
Tip
|
a valid pom <scm> also allows other services like Clojars to point back to your release’s sources.
|
Note
|
|
An example <scm>
entry from metosin/malli
:
<scm>
<url>https://github.com/metosin/malli</url>
<connection>scm:git:git://github.com/metosin/malli.git</connection>
<developerConnection>scm:git:ssh://git@github.com/metosin/malli.git</developerConnection>
<tag>0.8.4</tag>
</scm>
Another from juxt/bidi
:
<scm>
<url>https://github.com/juxt/bidi</url>
<connection>scm:git:git://github.com/juxt/bidi.git</connection>
<developerConnection>scm:git:ssh://git@github.com/juxt/bidi.git</developerConnection>
<tag>d1bfcc9c4fe247b8ada19cd7ee25acd81dd93f26</tag>
</scm>
Cljdoc will look at the <url>
and the <tag>
:
-
<url>
points to your hosted git repo -
<tag>
is a valid pointer to the git revision of your release’s sources. It can be a git tag, or commit sha.
Tip
|
You can optionally override the revision for articles and docstring format. |
Note
|
We strongly recommend you explicitly specify the <tag> in your pom.xml for cljdoc and other tools.But… If you do not specify a <tag> , cljdoc will search for a version tag based on the artifact version.
For artifact version 1.2.3 it will look for a git tag 1.2.3 (else v1.2.3 ).
|
Note
|
Cljdoc will assume a found version tag is equivalent to <tag> even when the <tag> specifies a commit sha.
|
Here are some common ways folks set <scm>
values:
-
By hand. You can edit a
pom.xml
manually when cutting a release, but this can be error-prone. -
Clojure tools build can be asked to populate the
<scm>
value. Cybermonday provides a good example of doing just that. -
Leiningen will automatically create the
<scm>
entry for you if you set the:scm
in yourproject.clj
. For example::scm {:name "git" :url "https://github.com/your-github-org/your-project"}
-
Boot also has support, pass the
:scm
option to thepom
task, an example.
Whatever method you choose, take care to ensure that your jar’s pom points back to the exact revision of its sources on git.
Sometimes you’ll want cljdoc to present minor adjustments after your library’s release commit. For examples:
-
a README that includes the git sha of the release will necessarily appear in a commit after the library release.
-
perhaps you’d like fix or edit an article without cutting a new release
-
you’d like to adjust your article table of contents
-
you might also want to change how cljdoc presents docstrings.
To support these scenarios, cljdoc recognizes the cljdoc-<version>
git tag.
For library version 1.2.3
cljdoc will look for git tag cljdoc-1.2.3
(or cljdoc-v1.2.3
) and import your articles from that commit instead of the default commit.
If you add/move a cljdoc-<version>
tag after the initial cljdoc build is complete, you can request a rebuild.
Tip
|
This affects all of and only: docstring format, article table of contents, and articles. Any changes, for example, to docstring content will require a new library release. |
Tip
|
You’ll want to make any adjustments before you start working on your next release. All articles are re-imported. |
When building your docs, cljdoc will look under the doc
(else docs
) directory for a cljdoc.edn
file in your library’s git repo.
You can use this configuration file to tell cljdoc more about your documentation.
-
:cljdoc.doc/tree
- Tells cljdoc what articles to present and in what hierarchy.
By default, cljdoc will automatically discover articles. -
:cljdoc/languages
- Tells cljdoc which languages your API uses.
By default, cljdoc will automatically detect languages based on the sources it finds in your jar. -
:cljdoc/docstring-format
- Tells cljdoc how you’d like your docstrings displayed.
By default, cljdoc will render docstrings from Markdown format. -
:cljdoc/include-namespaces-from-dependencies
- Tells cljdoc to amalgamate API docs from multiple modules.
Rarely used, but very useful when your project is made up of modules.
As an example, a version of honeysql's cljdoc.edn
{:cljdoc.doc/tree
[["Readme" {:file "README.md"}]
["Changes" {:file "CHANGELOG.md"}]
["Getting Started" {:file "doc/getting-started.md"}
["General Reference" {:file "doc/general-reference.md"}]
["SQL Clause Reference" {:file "doc/clause-reference.md"}]
["SQL Operator Reference" {:file "doc/operator-reference.md"}]
["SQL 'Special Syntax'" {:file "doc/special-syntax.md"}]
["PostgreSQL Support" {:file "doc/postgresql.md"}]
["Extending HoneySQL" {:file "doc/extending-honeysql.md"}]]
["Differences from 1.x" {:file "doc/differences-from-1-x.md"}]]}
See also: badges.
Tip
|
If you are locally previewing your docs, there’s no need to replace https://cljdoc.org with some localhost version.
Cljdoc will automatically make these URLs work locally.
|
-
When linking from article to article, use relative or root-relative links. Cljdoc will rewrite built article to article links automatically. Markdown examples:
-
[root relative link](/doc/some-doc.md)
-
[relative link](other-doc.md)
-
-
When linking from docstring to article, use root relative links. Markdown example:
-
[root relative link](/doc/some-doc.md)
-
-
When linking from outside your git repo:
-
doc home page
-
a specific doc in the current release, uses article slugs
-
a specific doc for release
0.7.5
, uses article slugs
-
Sometimes you’ll want to link to a var or a namespace in your library’s API docs on cljdoc.
You can link to other namespaces and functions within your libary from your markdown docstrings using the [[wikilink]]
syntax.
Examples:
Wikilink | Links to API docs for |
---|---|
|
|
|
|
|
|
Note
|
|
Use the full cljdoc API URL when linking to from an article or from outside your git repo.
For example to link to namespace malli.core
in version 0.7.5 use:
https://cljdoc.org/d/metosin/malli/0.7.5/api/malli.core
You can replace the explicit version with CURRENT
.
For example, to link to malli.core/explain
in the current version use:
https://cljdoc.org/d/metosin/malli/CURRENT/api/malli.core#explain
CURRENT
will be replaced with:
-
the current version the user is already viewing on cljdoc
-
the latest available version of the library when the user is navigating to cljdoc from some outside source
Cljdoc will document all namespaces and public vars it finds.
To exclude namespaces and/or vars from API documentation, annotate them with :no-doc
metadata:
(defn ^:no-doc hidden "Won't see me on cljdoc.org!" [x])
(ns ^:no-doc namespace.hidden
"This ns shouldn't show in the docs.")
(ns namespace.hidden
"This ns shouldn't show in the docs."
{:no-doc true})
Cljdoc will auto-detect which languages your library supports based on the types of source files it finds.
You can choose to override this auto-detection in your doc/cljdoc.edn
file via the :cljdoc/languages
option.
Example :cljdoc/languages value |
API Analysis run for |
---|---|
|
Clojure only |
|
ClojureScript only |
|
Both Clojure and ClojureScript |
|
Dependent upon source files found in your library, the default behavior. |
Example usage:
{:cljdoc/languages ["clj"]}
Cljdoc discovers your API via dynamic runtime analysis. It will try to load all namespaces found in your jar. If a dependency is not found, the load, and therefore API analysis, will fail.
If you include namespaces that require additional/optional dependencies, make sure you declare them in your pom.xml
.
If these dependencies are expected to be provided by, for example, some container or JVM, mark them with a scope
of "provided"
in our pom.xml
.
Provided dependencies are skipped at runtime, but inform cljdoc they are required for API analysis.
Tip
|
You can express provided in a project.clj , for example.
The deps.edn file does not support scoping, you’ll have to express these directly in your pom.xml .
|
Cljdoc will automatically search Clojars and Maven Central for dependencies.
If any of your library’s dependencies are hosted elsewhere, those maven repositories will need to be specified in your pom.xml
.
This includes any transitive dependencies.
Docstrings are rendered from Markdown by default.
You can choose to override this behaviour in your doc/cljdoc.edn
file via the :cljdoc/docstring-format
option.
Valid values are:
-
:markdown
- the default, an option to view "raw docstring" as plaintext is available to the user. -
:plaintext
- presents only the raw docstring.
Consider these recommendations when writing your docstrings in markdown format:
-
Backtick-Quote
`
function arguments & special keywords tomake
themstand
outmore
-
Link to other functions using
[[wikilink]]
syntax -
Include small examples using markdown fenced
```Clojure … ```
code blocks -
Use Markdown tables to describe complex options maps
-
You can include images and links to articles, just be sure to use git repo root-relative links (links that start with a
/
):-
![my image](/dir1/dir2/image1.png)
-
[my article](/dir1/dir2/article.adoc)
-
Any HTML embedded within docstrings is escaped.
Libraries often include additional guides and tutorials in markup files. Cljdoc calls these articles.
For cljdoc to find your articles:
-
They must be stored inside your project’s git repository
-
Your git repository must be properly linked to your git sources
This allows cljdoc to retrieve article files at the revision/commit of the release.
Cljdoc hosted articles will have their links rewritten to link back to cljdoc. All links that work on GitHub should also work on cljdoc.
If your git repository does not contain a doc tree configuration, cljdoc will automatically include:
-
README.md
elseREADME.adoc
- filename search is case insensitive-
Title is
Readme
-
-
CHANGELOG.md
elseCHANGELOG.adoc
- filename search is case insensitive-
Title is
Changelog
-
-
Markup articles from your
doc/
elsedocs/
folder-
The title is read from the file’s first heading, and failing that, be based on the article filename. There will be no nesting and articles will be ordered alphabetically by filename.
-
Tip
|
Use filenames prefixed with digits like 01-intro.md to define the order of articles.
|
If you need more control, use a doc/cljdoc.edn
file to specify a tree of articles.
Assuming you have a directory doc/
in your repository as follows:
doc/ getting-started.md installation.md configuration.md
You can explicitly add these articles to your cljdoc build by with the following doc/cljdoc.edn
file:
{:cljdoc.doc/tree [["Readme" {:file "README.md"}]
["Getting Started" {:file "doc/getting-started.md"}
["Installation" {:file "doc/installation.md"}]]
["Configuration" {:file "doc/configuration.md"}]]}
Your articles will be presented with the following hierarchy and titles:
├── Readme ├── Getting Started │ └── Installation └── Configuration
Tip
|
Cljdoc will always present the readme and changelog articles first. |
Important
|
The resulting URLs for those articles will be based on the title provided in the cljdoc.edn file and not on the filename or title within the article file.
|
See also: verifying articles
Slugs for articles are currently based on the article title. Titles can be explicitly configured or discovered.
Similar to env-github
on GitHub, cljdoc will set an env-cljdoc
attribute when
rendering your AsciiDoc file. This allows you to hide or show sections
of your document or set configuration parameters.
As an example, this AsciiDoctor snippet:
ifdef::env-cljdoc[]
THIS WILL BE SHOWN ON CLJDOC
endif::[]
ifndef::env-cljdoc[]
THIS WILL BE SHOWN EVERYWHERE ELSE
endif::[]
will render as so:
THIS WILL BE SHOWN EVERYWHERE ELSE
You can preview what your docs will look like before a Clojars release by running cljdoc locally.
If you are already publishing -SNAPSHOT
releases to Clojars, this can also be a useful way to experiment/preview on cljdoc.
We recommend that you populate <scm>
<tag>
in your pom.xml
with the git commit sha of your snapshot release.
Cljdoc does not automatically build snapshot releases, but they will show up in the library search result. Upon selecting a snapshot release, cljdoc will offer to build its docset.
By its nature, a snapshot release will likely have many releases under the same version. You can choose to rebuild for against the current releases.
Sometimes people forget to update the paths after moving files around, we recommend you add the following to your CI setup:
curl -fsSL https://raw.githubusercontent.com/cljdoc/cljdoc/master/script/verify-cljdoc-edn | bash -s doc/cljdoc.edn
We have a Cljdoc check action you can incorporate into your CI workflows.
-
Automatically
-
Every 60 seconds, cljdoc reaches out to clojars to discover new releases.
-
Every 10 minutes, it queues new releases to build
-
-
By request at cljdoc.org
-
If cljdoc has not already built a requested version of a library, you are given the option to build it from cljdoc.org.
-
-
By rebuild request at cljdoc.org
-
By REST request
-
An automated release process can trigger a build via rest trigger a cljdoc build via REST.
-
Some libraries are made up of submodule libraries. Cljdoc provides some support for these types of libraries.
To include API documentation for some or all of an artifact’s submodule artifacts, specify their maven coordinates under :cljdoc/include-namespaces-from-dependencies
:
{:cljdoc/include-namespaces-from-dependencies
[metosin/reitit
metosin/reitit-core
metosin/reitit-ring
metosin/reitit-spec
metosin/reitit-schema
metosin/reitit-swagger
metosin/reitit-swagger-ui]}
Note
|
To be included, each dependency must also be specified as a maven dependency of the project itself (in the project’s deps.edn , project.clj , etc).
The project’s resulting POM file will be used to load API information for the correct version.
|
Tip
|
Reitit is a great example reference for a project with submodules. |
Warning
|
If analysis for a specified dependency has failed or hasn’t been run, its API documentation will not appear on cljdoc. |
Sometimes a single git repository will be the source for multiple maven/clojars artifacts.
Each of these artifacts will point back to the same single git repository and therefore the same cljdoc.edn
.
Cljdoc allows for a distinct config for each of these artifacts.
Specify cljdoc.edn
config as normal for your primary library.
For each submodule libary, include config under symbol submodule-group-id/submodule-artifact-id
.
Here’s an example from clj-otel:
{:cljdoc/languages ["clj"]
:cljdoc.doc/tree [["Introduction" {:file "README.adoc"}]
["Tutorial" {:file "doc/tutorial.adoc"}]
["Guides" {:file "doc/guides.adoc"}]
["API & Reference" {:file "doc/reference.adoc"}]
["Concepts" {:file "doc/concepts.adoc"}]
["Examples" {:file "doc/examples.adoc"}]
["Changelog" {:file "CHANGELOG.adoc"}]]
com.github.steffan-westcott/clj-otel-contrib-aws-resources {:cljdoc.doc/tree [["README" {:file "clj-otel-contrib-aws-resources/README.adoc"}]]}
com.github.steffan-westcott/clj-otel-contrib-aws-xray-propagator {:cljdoc.doc/tree [["README" {:file "clj-otel-contrib-aws-xray-propagator/README.adoc"}]]}
com.github.steffan-westcott/clj-otel-exporter-jaeger-grpc {:cljdoc.doc/tree [["README" {:file "clj-otel-exporter-jaeger-grpc/README.adoc"}]]}
com.github.steffan-westcott/clj-otel-exporter-jaeger-thrift {:cljdoc.doc/tree [["README" {:file "clj-otel-exporter-jaeger-thrift/README.adoc"}]]}
com.github.steffan-westcott/clj-otel-exporter-logging {:cljdoc.doc/tree [["README" {:file "clj-otel-exporter-logging/README.adoc"}]]}
com.github.steffan-westcott/clj-otel-exporter-logging-otlp {:cljdoc.doc/tree [["README" {:file "clj-otel-exporter-logging-otlp/README.adoc"}]]}
com.github.steffan-westcott/clj-otel-exporter-otlp {:cljdoc.doc/tree [["README" {:file "clj-otel-exporter-otlp/README.adoc"}]]}
com.github.steffan-westcott/clj-otel-exporter-prometheus {:cljdoc.doc/tree [["README" {:file "clj-otel-exporter-prometheus/README.adoc"}]]}
com.github.steffan-westcott/clj-otel-exporter-zipkin {:cljdoc.doc/tree [["README" {:file "clj-otel-exporter-zipkin/README.adoc"}]]}
com.github.steffan-westcott/clj-otel-extension-trace-propagators {:cljdoc.doc/tree [["README" {:file "clj-otel-extension-trace-propagators/README.adoc"}]]}
com.github.steffan-westcott/clj-otel-instrumentation-resources {:cljdoc.doc/tree [["README" {:file "clj-otel-instrumentation-resources/README.adoc"}]]}
com.github.steffan-westcott/clj-otel-instrumentation-runtime-telemetry-java8 {:cljdoc.doc/tree [["README" {:file "clj-otel-instrumentation-runtime-telemetry-java8/README.adoc"}]]}
com.github.steffan-westcott/clj-otel-instrumentation-runtime-telemetry-java17 {:cljdoc.doc/tree [["README" {:file "clj-otel-instrumentation-runtime-telemetry-java17/README.adoc"}]]}
com.github.steffan-westcott/clj-otel-sdk {:cljdoc.doc/tree [["README" {:file "clj-otel-sdk/README.adoc"}]]}
com.github.steffan-westcott/clj-otel-sdk-extension-jaeger-remote-sampler {:cljdoc.doc/tree [["README" {:file "clj-otel-sdk-extension-jaeger-remote-sampler/README.adoc"}]]}}