GroovyDoc generates API documentation from your source code. It plays the role the Javadoc tool plays in the Java ecosystem, but accepts both .groovy and .java sources and adds conveniences suited to Groovy.

The documentation generator is driven from the command line, from Apache Ant, or from build-tool wrappers such as the GMavenPlus Maven plugin. The sections below cover the everyday authoring and invocation patterns; Advanced topics collects the lesser-used features.

1. Writing doc comments

GroovyDoc recognises three forms of doc comment, all of which can coexist in the same source file:

  • Traditional Javadoc /* …​ `/` block comments.

  • JEP 467-style Markdown comments using runs of /// line prefixes.

  • Runtime-retained Javadoc /*@ …​ `/` block comments, whose content is reflectable at runtime via the @Groovydoc annotation (see Runtime Groovydoc).

1.1. Comment forms

1.1.1. Traditional Javadoc

/**
 * Summary sentence. More description.
 *
 * @param name the subject to greet
 * @return the greeting
 */
String greet(String name) { "Hello, $name" }

Leading prefixes on each line are stripped. The first sentence (up to the first period followed by whitespace) is used as the short summary on index/package pages.

1.1.2. JEP 467 Markdown (///)

Each line of the run starts with ///. Inside the comment, CommonMark Markdown is supported — headings, bullets, emphasis, links, and fenced code blocks all render as you would expect:

/// # Greet
///
/// Returns a friendly greeting. Supports the usual inline tags:
/// {@link String} and {@code greet} still work.
///
/// ```groovy
/// assert greeter.greet('world') == 'Hello, world'
/// ```
///
/// @param name the subject to greet
/// @return the greeting
String greet(String name) { "Hello, $name" }

Markdown is rendered through CommonMark. Headings are shifted down by two levels (so # becomes <h3>) to fit under the page’s existing title and section banners. Inline Javadoc tags like {@link …​} are preserved inside Markdown bodies. {@link …​} tokens appearing inside fenced code blocks are left literal — the fence is treated as code, not documentation.

For the full Markdown syntax and semantics, see JEP 467 and CommonMark.

1.1.3. Runtime Groovydoc (/**@)

If the comment opens with /@ instead of /, Groovy’s parser can retain the raw comment text as a groovy.lang.@Groovydoc annotation on the enclosing class/method/field. Enable the feature through the compiler option runtimeGroovydoc; see Runtime Groovydoc.

1.2. Block tags

Block tags appear at the end of the comment, one per paragraph, leading with @. Common tags:

Tag Purpose

@param <name> <description>

Describes a parameter. Use @param <T> for a type parameter.

@return <description>

Describes the return value.

@throws <exception> <description>, @exception <exception> <description>

Describes an exception the method might throw.

@since <version>

Indicates when the feature was added.

@author <name>

Author of the element. Rendered only when -author is enabled.

@version <text>

Version information.

@deprecated <explanation>

Marks the element as deprecated; recommend a replacement.

@see <reference>

Adds a "See Also" entry. The reference is a class or member.

@apiNote <text>

Guidance intended for callers of the API.

@implSpec <text>

Contract that overriders must preserve.

@implNote <text>

Non-contract implementation detail.

Multiple @param, @throws, and @see entries are collated under a single heading in the rendered output.

1.3. Inline tags

Inline tags appear within a comment body and are expanded in place.

Tag Purpose

{@link <reference>}

Cross-reference to a class or member. Produces a hyperlink.

{@code <text>}

Renders the text in a monospaced code style. HTML metacharacters are escaped.

{@literal <text>}

Renders the text verbatim without code styling.

{@value #FIELD}, {@value Class#FIELD}

Inlines the value of a compile-time-constant field. Same-class references and cross-class references both work. On a constant field’s own comment, bare {@value} inlines that field’s own value.

{@inheritDoc}

Inherits the parent class’s/interface’s corresponding doc.

{@snippet …​}

Embeds a code snippet. See {@snippet} under advanced topics.

{@docRoot}

Path to the root of the generated documentation. Useful when writing a relative link that must work from pages at any depth.

2. Running groovydoc

2.1. The groovydoc command line tool

The groovydoc command line invocation:

groovydoc [options] [packagenames] [sourcefiles]

Most commonly-used options:

Short version Long version Description

-d

--destdir <dir>

Destination directory for output files

-sourcepath <pathlist>

Directories to find source files (platform path separator)

-classpath, -cp

--classpath

Where to find class files (must be first argument)

-public

Show only public classes and members

-protected

Show protected/public classes and members (default)

-package

Show package/protected/public classes and members

-private

Show all classes and members

-charset <charset>

Charset for cross-platform viewing of generated HTML

-fileEncoding <charset>

Charset for generated documentation files

-doctitle <html>

Title for the overview page

-windowtitle <text>

Browser window title

-header <html>

Include header text on each page

-footer <html>

Include footer text on each page

-overview <file>

Read overview documentation from HTML file

-exclude <pkglist>

Exclude listed packages (colon-separated)

-noscripts

Don’t process Groovy Scripts

-author

Include @author paragraphs

-stylesheetfile <path>

Replace the default stylesheet with a supplied one

-addStylesheet <path>

Add a stylesheet alongside the default (can be given multiple times with comma-separated values)

-theme <mode>

Theme: auto (default, follow OS), light, or dark

-syntaxHighlighter <name>

Client-side syntax highlighter: prism (bundled) or none (default)

-preLanguage <lang>

Default Prism language id for unattributed <pre> blocks in doc comments. When set, a post-render pass wraps their bodies so Prism highlights them (see Highlighting plain <pre> blocks).

-showInternal

Include members annotated with groovy.transform.@Internal (hidden by default)

-noindex

Skip generating the alphabetical index page

-nodeprecatedlist

Skip generating the deprecated list

-nohelp

Skip generating the help page

-notimestamp

Don’t include generation timestamp in output

-noversionstamp

Don’t include Groovy version in output

-nomainforscripts

Don’t include the implicit public static void main method for scripts

-help, -h

--help

Display help message

-verbose, -quiet, --debug

Adjust logging verbosity

--version

Display the version

-javaVersion <version>

Language version for parsed Java files (e.g. JAVA_17)

2.2. The groovydoc Ant task

The Ant task exposes the same feature set. You will need the task defined before invoking it:

<taskdef name         = "groovydoc"
         classname    = "org.codehaus.groovy.ant.Groovydoc"
         classpathref = "my.classpath"/>

where my.classpath references the Groovy distribution jars (groovy-VERSION.jar, groovy-ant-VERSION.jar, groovy-groovydoc-VERSION.jar, plus any modules and transitive dependencies you use).

2.2.1. <groovydoc> attributes

Attribute Description Required

destdir

Location to write generated documentation to.

Yes

sourcepath

Directories to scan for source files.

No

packagenames

Comma-separated list of package specs (wildcards allowed, e.g. com.foo.**).

No

excludePackageNames

Comma-separated (or colon-separated) list of package specs to exclude.

No

windowtitle

Browser window title.

No

doctitle

HTML shown at the top of the overview page.

No

header, footer

HTML shown at the top/bottom of every page.

No

overview

HTML file read as the overview page.

No

charset

Charset for cross-platform viewing of generated HTML.

No

fileEncoding

Charset used when writing the generated files.

No

author

Include @author paragraphs. Defaults to true.

No

processScripts

Process Groovy scripts. Defaults to true; set to false to mirror the CLI -noscripts flag.

No

includeMainForScripts

Include the synthetic public static void main method when documenting scripts. Defaults to true; set to false to mirror the CLI -nomainforscripts flag.

No

stylesheetFile

Replace the default stylesheet with a supplied one.

No

private

Show all classes and members (including private ones).

No

public, protected, package

Set individually to control the visibility scope; equivalent to the CLI -public, -protected, -package flags.

No

access

Alternative to the boolean scope attributes above. Accepts public, protected, package, or private.

No

javaVersion

Language version for Java source files.

No

extensions

Colon-separated source extensions (default .java:.groovy:.gv:.gvy:.gsh).

No

use

Legacy Javadoc option accepted for parity. Has no effect on groovydoc output.

No

showInternal

Include members annotated with groovy.transform.@Internal.

No

noIndex, noDeprecatedList, noHelp

Suppress the matching auxiliary page.

No

syntaxHighlighter

prism or none (default).

No

theme

Theme lock: auto (default), light, or dark.

No

preLanguage

Default Prism language for unattributed <pre> blocks in doc comments. See Highlighting plain <pre> blocks.

No

noTimestamp, noVersionStamp

Omit the matching stamp from output.

No

2.2.2. <groovydoc> nested elements

Create cross-references to external Javadoc/groovydoc output. See Linking to external APIs.

Attribute Description Required

packages

Comma-separated list of package prefixes.

Yes

href

Base URL of the external site.

Yes

module

JPMS module name; inserted as a path segment for modular Javadoc layouts.

No

<addStylesheet>

Add an extra stylesheet alongside the default. Repeat the element to add multiple stylesheets.

Attribute Description Required

file

Path to the stylesheet file.

Yes

2.2.3. Ant task example

<taskdef name           = "groovydoc"
         classname      = "org.codehaus.groovy.ant.Groovydoc"
         classpathref   = "path_to_groovy_all"/>

<groovydoc destdir      = "${docsDirectory}/gapi"
           sourcepath   = "${mainSourceDirectory}"
           packagenames = "**.*"
           use          = "true"
           windowtitle  = "${title}"
           doctitle     = "${title}"
           header       = "${title}"
           footer       = "${docFooter}"
           overview     = "src/main/overview.html"
           private      = "false">
        <link packages="java.,org.xml.,javax.,org.xml." href="https://docs.oracle.com/javase/8/docs/api/"/>
        <link packages="org.apache.tools.ant."          href="https://docs.groovy-lang.org/docs/ant/api/"/>
        <link packages="org.junit.,junit.framework."    href="https://junit.org/junit4/javadoc/latest/"/>
        <link packages="groovy.,org.codehaus.groovy."   href="https://docs.groovy-lang.org/latest/html/api/"/>
</groovydoc>

Running the task from Groovy via AntBuilder works the same way.

<link> (Ant) and -link (CLI) let cross-references resolve to an external Javadoc/groovydoc site. Packages are matched by the packages attribute as a comma-separated list of prefixes; when a documented reference matches one of the prefixes the link goes to the configured href base.

The module attribute on <link> supports modular Javadoc layouts, where an external site places each JPMS module’s docs under a module-named subdirectory. With module="java.base" and href="https://docs.oracle.com/en/java/javase/17/docs/api/", a link to java.lang.Object resolves to https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Object.html.

4. Customising the output

4.1. Stylesheets

Two mechanisms cover most customisation needs:

  • -stylesheetfile <path> (CLI) / stylesheetFile="…​" (Ant) — replaces the default stylesheet. The supplied file is copied verbatim over stylesheet.css in the output. If the file has no dark-mode support of its own, the generated docs will be light-only regardless of the theme settings below.

  • -addStylesheet <path> (CLI) / <addStylesheet file="…​"/> (Ant) — adds an extra stylesheet alongside the default. The default is still loaded and supplies the baseline look; the added stylesheet layers on top. This is the safer choice for theme tweaks.

Author stylesheets can opt into the baseline palette by referencing the default stylesheet’s CSS custom properties (--fg, --bg, --link, --bg-panel, --border, --caption-bg, and related semantic tokens). Doing so makes the added stylesheet automatically dark-mode aware.

4.2. Theme

-theme <mode> / theme="…​" controls the palette strategy:

  • auto (default) — the generated stylesheet emits a prefers-color-scheme media query. Each reader’s browser picks the light or dark palette that matches their OS preference. Syntax highlighting (if enabled) switches Prism themes in sync.

  • light — locks the output to the light palette regardless of OS preference.

  • dark — locks the output to the dark palette regardless of OS preference.

auto is the right choice for public-facing docs that should adapt to the reader. light and dark are useful for branded sites where a consistent look matters more than honouring OS preference.

4.3. Syntax highlighting

-syntaxHighlighter prism / syntaxHighlighter="prism" enables client-side syntax highlighting for {@snippet} blocks and Markdown fenced code blocks. Prism.js is bundled and covers at minimum Groovy, Java, XML, JSON, YAML, TOML, SQL, CSV, Markdown, JavaScript, and regex. The light/dark theme selection tracks the theme setting automatically. The default is none (no highlighting); code blocks are rendered as plain preformatted text.

4.4. Highlighting plain <pre> blocks

Doc comments written before the {@snippet} era often use bare <pre>…​</pre> wrappers for code samples. Prism only walks <code> descendants of language-classed elements, so a bare <pre> with prose inside is skipped even when -syntaxHighlighter=prism is on. The -preLanguage <lang> option (CLI) or preLanguage="lang" attribute (Ant task) closes that gap without touching source files:

groovydoc -syntaxHighlighter prism -preLanguage groovy ...

When set, a post-render pass rewrites each unattributed <pre>body</pre> to <pre class="language-xxx"><code>body</code></pre>, using the configured language id. A <pre class="language-xxx"> that lacks an inner <code> is also completed with a <code> wrapper so hand-authored language-classed blocks highlight whether or not the author remembered the nested <code>. <pre> tags with any existing attribute (authored class="language-sql", id="…​", or similar) are left untouched.

The option is off by default; unset, no rewriting occurs.

4.5. Disable optional pages

GroovyDoc generates auxiliary pages by default:

  • index-all.html — alphabetical index of every class and member

  • deprecated-list.html — everything marked @deprecated

  • help-doc.html — explanation of the page layout

Any of these can be suppressed with -noindex, -nodeprecatedlist, -nohelp (CLI) or the corresponding noIndex, noDeprecatedList, noHelp Ant attributes. When suppressed, the page is not generated and navigation bars on other pages omit the corresponding link.

5. GMavenPlus Maven plugin

GMavenPlus is a Maven plugin with goals that drive groovydoc. Consult the plugin documentation for the current list of options it exposes.

6. Advanced topics

6.1. {@snippet} code snippets

{@snippet} embeds a code sample that renders as a preformatted block and, when syntax highlighting is enabled, is coloured according to its declared language. Three forms are supported:

6.1.1. Inline body

/**
 * {@snippet lang="groovy" :
 * def greet(name) { "Hello, $name" }
 * greet('world')
 * }
 */

The language is optional; when set, it becomes the Prism language class used for syntax highlighting. Any text from the opening brace to the matching closing brace is the snippet body.

6.1.2. Brace balancing in the inline form

Body parsing is a simple brace counter: the parser starts at depth 1 on the { after {@snippet, increments on every { it sees, decrements on every }, and the matching close is reached when depth returns to zero. The counter has no awareness of string literals, character escapes, or comments, so every { in the body must have a matching }, including braces inside GString interpolations and string literals. Code like "${x}" or catalog.each { book → …​ } is fine — GString ${…​} blocks and closure bodies already balance. A lone { or } inside a plain string, however, will confuse the parser:

/**
 * {@snippet lang="groovy" :
 * println '}'    // <-- stray literal } terminates the snippet body here
 * }
 */

Three workarounds when an example really needs an unbalanced literal brace:

  • Rewrite the example so all braces balance (often trivially possible, e.g. println '${"}"}' or a string-concatenation alternative).

  • Move the sample into a file and use the external form ({@snippet file="Example.groovy"}), which reads the file verbatim without brace-balanced parsing.

  • Write the } as the HTML entity }, which groovydoc counts as a single non-brace character during body extraction but renders as } in the output.

6.1.3. External file reference

Place the source of the snippet in a snippet-files/ subdirectory of the current package, then reference it:

/** {@snippet file="GreetExample.groovy"} */

The snippet-files/ directory is discovered via the -sourcepath. The file is copied to the output site verbatim so that the snippet remains browsable in the rendered docs.

A region="name" attribute selects a slice of the file bounded by // @start region="name" and // @end region="name" marker comments.

Two author-facing conveniences apply to the external form:

  • Language inference from file extension — when no explicit lang="…​" attribute is given, the Prism language class is derived from the referenced file’s extension. The recognised extensions are .groovy / .gvy / .gy / .gsh (groovy), .java, .xml / .html / .htm (xml-doc), .json, .yaml / .yml, .toml, .sql, .csv, .md / .markdown, .properties, and .js (javascript). Explicit lang= still wins when both are present.

  • License-header auto-strip — external snippet files typically carry a license or copyright notice as their first block comment, which isn’t useful in the rendered output. If the file begins with a leading /* …​ */ block comment whose text contains either "Licensed" or "Copyright", the block is stripped before rendering (covers Apache, MIT, BSD, GPL and most proprietary notices). Files whose first content isn’t a license-looking block comment are left verbatim. To preserve a matching header (or suppress the strip for a file that happens to match), add keepHeader=true:

    /** {@snippet file="GreetExample.groovy" keepHeader=true} */

6.1.4. Markup comments inside a snippet body

Markup comments let snippet authors highlight, replace, or link portions of the code without changing the source itself:

Directive Effect

// @highlight [substring="text"|regex="pattern"] [type="bold|italic|highlighted"]

Wrap matches in <b>/<i>/<mark>. Type defaults to bold.

// @replace [substring="text"|regex="pattern"] replacement="text"

Replace matching text in the rendered output.

// @link [substring="text"|regex="pattern"] target="Class[#member]"

Turn matches into anchors pointing at the referenced element.

// @start region="name", // @end [region="name"]

Define a named region for the external-file form, or as a scoping bound for any of the above directives.

A directive written on its own line applies to the next code line. A directive written at the end of a code line (after the code) applies to that line’s code portion. Adding a region="name" attribute to a directive activates it until the matching // @end. Directive comment lines are stripped from the rendered output.

For the complete semantics see JEP 413.

6.2. Class hierarchy tree pages

GroovyDoc generates a global overview-tree.html and per-package package-tree.html showing class and interface hierarchies. Classes are rooted at java.lang.Object; interfaces and traits form a separate tree. External ancestors (types the tool can’t see) render as plain text joining documented classes up the chain.

6.3. Runtime Groovydoc (/**@)

A doc comment whose opening marker is /@ instead of / can be retained as runtime metadata. Enable it by setting the compiler option:

compilerConfiguration.setOptimizationOptions(
    [(CompilerConfiguration.RUNTIME_GROOVYDOC): true]
)

When enabled, the parser attaches the raw comment text (still in source form — including /*@, per-line , and */) to the declaration as a groovy.lang.@Groovydoc annotation. Readers access the text reflectively:

assert SomeClass.class.groovydoc.content.contains('class summary')

/@ comments do not need to be marked specially to participate in normal groovydoc HTML generation; they render identically to /.

6.4. doc-files/ and snippet-files/

Each package may contain a doc-files/ subdirectory whose content is copied verbatim into the rendered output under the same package path. Useful for bundling images, diagrams, and supplementary HTML alongside the generated pages.

The sibling convention snippet-files/ is used by {@snippet file=…​. Both conventions are sourced from -sourcepath directories and preserve nested subdirectories.

6.5. Java source version

-javaVersion (CLI) / javaVersion (Ant attribute) declares the language level at which .java source files are parsed. The accepted values are the names of the ParserConfiguration.LanguageLevel enum — for example JAVA_8, JAVA_17, JAVA_21.

6.6. Custom templates

The default template set can be replaced by extending Groovydoc in a small Java class:

package org.codehaus.groovy.tools.groovydoc;

import org.codehaus.groovy.ant.Groovydoc;

public class CustomGroovyDoc extends Groovydoc {

    @Override
    protected String[] getClassTemplates() {
        return new String[]{"path/to/custom/classDocName.html"};
    }
}

The following methods can be overridden:

  • getClassTemplates — class-level templates

  • getPackageTemplates — package-level templates

  • getDocTemplates — top-level (overview, index, tree, etc.) templates

The list of default templates is in org.codehaus.groovy.tools.groovydoc.gstringTemplates.GroovyDocTemplateInfo.

Having extended the task, you then register it as an Ant task under the same name:

<taskdef name         = "groovydoc"
         classname    = "org.codehaus.groovy.tools.groovydoc.CustomGroovyDoc"
         classpathref = "path_to_groovy_all"/>

Template customisation is provided as is — the template APIs are subject to change between releases.