---
title: "Releases"
weight: 20
---

GoReleaser can create a GitHub/GitLab/Gitea release with the current tag, upload
all the artifacts and generate the changelog based on the new commits since the
previous tag.

Let's see what can be customized in the `release` section for GitHub:

```yaml {filename=".goreleaser.yaml"}
release:
  # Repository in which the release will be created.
  # Default: extracted from the origin remote URL or empty if its private hosted.
  # You can set only one of either 'github', 'gitlab', or 'gitea'.
  github: # OR gitlab OR gitea
    owner: user
    name: repo

    # Token to use for this release, instead of the default one.
    #
    # Useful when the release repository requires a different token than the
    # one used to build from - for instance, when publishing to a repository
    # in another organization.
    #
    # {{< g_inline_version "v2.17" >}}
    # Templates: allowed (environment variables only).
    token: "{{ .Env.RELEASE_GITHUB_TOKEN }}"

  # IDs of the archives to use.
  # Empty means all IDs.
  #
  # Default: [].
  ids:
    - foo
    - bar

  # If set to true, will not auto-publish the release.
  # Note: all GitHub releases start as drafts while artifacts are uploaded.
  # Available only for GitHub and Gitea.
  draft: true

  # Whether to remove existing draft releases with the same name before creating
  # a new one.
  #
  # Only effective if `draft` is set to true.
  # Available only for GitHub.
  replace_existing_draft: true

  # Whether to use an existing draft release as the target release.
  #
  # Available only for GitHub.
  # {{< g_inline_version "v2.5" >}}
  use_existing_draft: true

  # Whether to remove an artifact that already exists.
  #
  # Available only for GitHub.
  # This might be a bit expensive (rate-limiting speaking), so it is only done
  # when the upload of an artifact fails with a 422 (which means it already
  # exists in the release).
  # We then grab the list of artifacts from the release, and delete the file
  # that matches the one we're trying to upload.
  # GoReleaser will then retry its upload.
  replace_existing_artifacts: true

  # Useful if you want to delay the creation of the tag in the remote.
  # You can create the tag locally, but not push it, and run GoReleaser.
  # It'll then set the `target_commitish` portion of the GitHub release to the
  # value of this field.
  # Only works on GitHub.
  #
  # Default: ''.
  # Templates: allowed.
  target_commitish: "{{ .Commit }}"

  # This allows to change which tag GitHub will create.
  # Usually you'll use this together with `target_commitish`, or if you want to
  # publish a binary from a monorepo into a public repository somewhere, without
  # the tag prefix.
  #
  # Note: if you change this, you might want to change 'url_template' in the
  # subsequent publishers and announcers.
  #
  # {{< g_inline_pro >}}
  # Default: '{{ .PrefixedTag }}'.
  # Templates: allowed.
  tag: "{{ .Tag }}"

  # If set, will create a release discussion in the category specified.
  #
  # Warning: do not use categories in the 'Announcement' format.
  #  Check https://github.com/goreleaser/goreleaser/issues/2304 for more info.
  #
  # Default: ''.
  discussion_category_name: General

  # If set to auto, will mark the release as not ready for production
  # in case there is an indicator for this in the tag e.g. v1.0.0-rc1
  # If set to true, will mark the release as not ready for production.
  # Default: false.
  prerelease: auto

  # If set to false, will NOT mark the release as "latest".
  # This prevents it from being shown at the top of the release list,
  # and from being returned when calling https://api.github.com/repos/OWNER/REPO/releases/latest.
  #
  # Available only for GitHub.
  #
  # Default: true.
  # Templates: allowed. {{< g_inline_version "v2.6" >}}
  make_latest: true

  # What to do with the release notes in case the release already exists.
  #
  # Valid options are:
  # - `keep-existing`: keep the existing notes
  # - `append`: append the current release notes to the existing notes
  # - `prepend`: prepend the current release notes to the existing notes
  # - `replace`: replace existing notes
  #
  # Default: `keep-existing`.
  mode: append

  # Header for the release body.
  #
  # Templates: allowed.
  header: |
    ## Some title ({{ .Date }})

    Welcome to this new release!

  # Header for the release body.
  #
  # {{< g_inline_pro >}}
  header:
    # Loads from an URL.
    from_url:
      # Templates: allowed.
      url: https://foo.bar/header.md
      headers:
        x-api-token: "${MYCOMPANY_TOKEN}"

    # Loads from a local file.
    # Overrides `from_url`.
    from_file:
      # Templates: allowed.
      path: ./header.md

  # Footer for the release body.
  #
  # Templates: allowed.
  footer: |
    ## Thanks

    Those were the changes on {{ .Tag }}!

  # Footer for the release body.
  #
  # {{< g_inline_pro >}}
  footer:
    # Loads from an URL.
    from_url:
      # Templates: allowed.
      url: https://foo.bar/footer.md
      headers:
        x-api-token: "${MYCOMPANY_TOKEN}"

    # Loads from a local file.
    # Overrides `from_url`.
    from_file:
      # Templates: allowed.
      path: ./footer.md

  # You can change the name of the release.
  #
  # Default: '{{.Tag}}' ('{{.PrefixedTag}}' on Pro).
  # Templates: allowed.
  name_template: "{{.ProjectName}}-v{{.Version}} {{.Env.USER}}"

  # You can disable this pipe in order to not create the release on any SCM.
  # Keep in mind that this might also break things that depend on the release
  # URL, for instance, homebrew taps.
  #
  # Templates: allowed.
  disable: true

  # Set this to true if you want to disable just the artifact upload to the SCM.
  # If this is true, GoReleaser will still create the release with the
  # changelog, but won't upload anything to it.
  #
  # Templates: allowed.
  skip_upload: true

  # Preflight checks run before the build, to surface likely problems early
  # instead of after a full build.
  #
  # {{< g_inline_version "v2.18-unreleased" >}}
  preflight:
    # Abort the release before building if a preflight check fails — for
    # instance, when the token lacks permission to publish, or the current tag
    # is already published as an immutable release that cannot be updated.
    #
    # When false (default), a failed check only logs a warning.
    #
    # Templates: allowed.
    fail_on_error: true

  # You can add extra pre-existing files to the release.
  # The filename on the release will be the last part of the path (base).
  # If another file with the same name exists, the last one found will be used.
  #
  # Templates: allowed.
  extra_files:
    - glob: ./path/to/file.txt
    - glob: ./glob/**/to/**/file/**/*
    - glob: ./glob/foo/to/bar/file/foobar/override_from_previous
    - glob: ./single_file.txt
      name_template: file.txt # note that this only works if glob matches 1 file only

  # Additional templated extra files to add to the release.
  # Those files will have their contents pass through the template engine,
  # and its results will be added to the release.
  #
  # {{< g_inline_pro >}}
  # Templates: allowed.
  templated_extra_files:
    - src: LICENSE.tpl
      dst: LICENSE.txt

  # Upload metadata.json and artifacts.json to the release as well.
  include_meta: true

```

If you need more info on a specific provider, follow along:

- [GitHub](/customization/publish/scm/github/)
- [GitLab](/customization/publish/scm/gitlab/)
- [Gitea](/customization/publish/scm/gitea/)

{{< g_templates >}}

## Custom release notes

You can specify a file containing your custom release notes, and pass it with
the `--release-notes=FILE` flag. GoReleaser will then skip its own release notes
generation, using the contents of your file instead. You can use Markdown to
format the contents of your file.

On Unix systems you can also generate the release notes in-line by using
[process substitution](https://en.wikipedia.org/wiki/Process_substitution). To
list all commits since the last tag, but skip ones starting with `Merge` or
`docs`, you could run this command:

```sh
goreleaser release --release-notes <(some_changelog_generator)
```

Some changelog generators you can use:

- [buchanae/github-release-notes](https://github.com/buchanae/github-release-notes)
- [miniscruff/changie](https://github.com/miniscruff/changie)

> [!NOTE]
> If you create the release before running GoReleaser, and the said release
> has some text in its body, GoReleaser will not override it with its release
> notes, unless you configure it to do so (e.g. `mode: replace`).
