blob: 030ffbfa146653708e16c1b49a0720fc9ba88490 [file] [log] [blame] [view]
<!--{
"Title": "Module release and versioning workflow"
}-->
When you develop modules for use by other developers, you can follow a workflow
that helps ensure a reliable, consistent experience for developers using the
module. This topic describes the high-level steps in that workflow.
For an overview of module development, see [Developing and publishing
modules](developing).
**See also**
* If you're merely wanting to use external packages in your code, be sure to
see [Managing dependencies](/doc/modules/managing-dependencies).
* With each new version, you signal the changes to your module with its
version number. For more, see [Module version numbering](/doc/modules/version-numbers).
## Common workflow steps {#common-steps}
The following sequence illustrates release and versioning workflow steps for an
example new module. For more about each step, see the sections in this topic.
1. **Begin a module** and organize its sources to make it easier for developers
to use and for you to maintain.
If you're brand new to developing modules, check out [Tutorial: Create a Go
module](/doc/tutorial/create-module).
In Go's decentralized module publishing system, how you organize your code
matters. For more, see [Managing module source](/doc/modules/managing-source).
1. Set up to **write local client code** that calls functions in the
unpublished module.
Before you publish a module, it's unavailable for the typical dependency
management workflow using commands such as `go get`. A good way to test your
module code at this stage is to try it while it is in a directory local to
your calling code.
See [Coding against an unpublished module](#unpublished) for more about
local development.
1. When the module's code is ready for other developers to try it out,
**begin publishing v0 pre-releases** such as alphas and betas. See
[Publishing pre-release versions](#pre-release) for more.
1. **Release a v0** that's not guaranteed to be stable, but which users can try
out. For more, see [Publishing the first (unstable) version](#first-unstable).
1. After your v0 version is published, you can (and should!) continue to
**release new versions** of it.
These new versions might include bug fixes (patch releases), additions to
the module's public API (minor releases), and even breaking changes. Because
a v0 release makes no guarantees of stability or backward compatibility, you
can make breaking changes in its versions.
For more, see [Publishing bug fixes](#bug-fixes) and [Publishing
non-breaking API changes](#non-breaking).
1. When you're getting a stable version ready for release, you **publish
pre-releases as alphas and betas**. For more, see [Publishing pre-release
versions](#pre-release).
1. Release a v1 as the **first stable release**.
This is the first release that makes commitments about the module's
stability. For more, see [Publishing the first stable
version](#first-stable).
1. In the v1 version, **continue to fix bugs** and, where necessary, make
additions to the module's public API.
For more, see [Publishing bug fixes](#bug-fixes) and [Publishing
non-breaking API changes](#non-breaking).
1. When it can't be avoided, publish breaking changes in a **new major version**.
A major version update -- such as from v1.x.x to v2.x.x -- can be a very
disruptive upgrade for your module's users. It should be a last resort. For
more, see [Publishing breaking API changes](#breaking).
## Coding against an unpublished module {#unpublished}
When you begin developing a module or a new version of a module, you won't yet
have published it. Before you publish a module, you won't be able to use Go
commands to add the module as a dependency. Instead, at first, when writing
client code in a different module that calls functions in the unpublished
module, you'll need to reference a copy of the module on the local file system.
You can reference a module locally from the client module's go.mod file by using
the `replace` directive in the client module's go.mod file. For more
information, see in [Requiring module code in a local
directory](managing-dependencies#local_directory).
## Publishing pre-release versions {#pre-release}
You can publish pre-release versions to make a module available for others to
try it out and give you feedback. A pre-release version includes no guarantee of
stability.
Pre-release version numbers are appended with a pre-release identifier. For more
on version numbers, see [Module version numbering](/doc/modules/version-numbers).
Here are two examples:
```
v0.2.1-beta.1
v1.2.3-alpha
```
When making a pre-release available, keep in mind that developers using the
pre-release will need to explicitly specify it by version with the `go get`
command. That's because, by default, the `go` command prefers release versions
over pre-release versions when locating the module you're asking for. So
developers must get the pre-release by specifying it explicitly, as in the
following example:
```
go get example.com/theirmodule@v1.2.3-alpha
```
You publish a pre-release by tagging the module code in your repository,
specifying the pre-release identifier in the tag. For more, see [Publishing a
module](publishing).
## Publishing the first (unstable) version {#first-unstable}
As when you publish a pre-release version, you can publish release versions that
don't guarantee stability or backward compatibility, but give your users an
opportunity to try out the module and give you feedback.
Unstable releases are those whose version numbers are in the v0.x.x range. A v0
version makes no stability or backward compatibility guarantees. But it gives
you a way to get feedback and refine your API before making stability
commitments with v1 and later. For more see, [Module version
numbering](version-numbers).
As with other published versions, you can increment the minor and patch parts of
the v0 version number as you make changes toward releasing a stable v1 version.
For example, after releasing a v.0.0.0, you might release a v0.0.1 with the
first set of bug fixes.
Here's an example version number:
```
v0.1.3
```
You publish an unstable release by tagging the module code in your repository,
specifying a v0 version number in the tag. For more, see [Publishing a
module](publishing).
## Publishing the first stable version {#first-stable}
Your first stable release will have a v1.x.x version number. The first stable
release follows pre-release and v0 releases through which you got feedback,
fixed bugs, and stabilized the module for users.
With a v1 release, you're making the following commitments to developers using
your module:
* They can upgrade to the major version's subsequent minor and patch releases
without breaking their own code.
* You won't be making further changes to the module's public API -- including
its function and method signatures -- that break backward compatibility.
* You won't be removing any exported types, which would break backward
compatibility.
* Future changes to your API (such as adding a new field to a struct) will be
backward compatible and will be included in a new minor release.
* Bug fixes (such as a security fix) will be included in a patch release or as
part of a minor release.
**Note:** While your first major version might be a v0 release, a v0 version
does not signal stability or backward compatibility guarantees. As a result,
when you increment from v0 to v1, you needn't be mindful of breaking backward
compatibility because the v0 release was not considered stable.
For more about version numbers, see [Module version numbering](/doc/modules/version-numbers).
Here's an example of a stable version number:
```
v1.0.0
```
You publish a first stable release by tagging the module code in your
repository, specifying a v1 version number in the tag. For more, see [Publishing
a module](publishing).
## Publishing bug fixes {#bug-fixes}
You can publish a release in which the changes are limited to bug fixes. This is
known as a patch release.
A _patch release_ includes only minor changes. In particular, it includes no
changes to the module's public API. Developers of consuming code can upgrade to
this version safely and without needing to change their code.
**Note:** Your patch release should try not to upgrade any of that module's own
transitive dependencies by more than a patch release. Otherwise, someone
upgrading to the patch of your module could wind up accidentally pulling in a
more invasive change to a transitive dependency that they use.
A patch release increments the patch part of the module's version number. For
more see, [Module version numbering](/doc/modules/version-numbers).
In the following example, v1.0.1 is a patch release.
Old version: `v1.0.0`
New version: `v1.0.1`
You publish a patch release by tagging the module code in your repository,
incrementing the patch version number in the tag. For more, see [Publishing a
module](publishing).
## Publishing non-breaking API changes {#non-breaking}
You can make non-breaking changes to your module's public API and publish those
changes in a _minor_ version release.
This version changes the API, but not in a way that breaks calling code. This
might include changes to a module’s own dependencies or the addition of new
functions, methods, struct fields, or types. Even with the changes it includes,
this kind of release guarantees backward compatibility and stability for
existing code that calls the module's functions.
A minor release increments the minor part of the module's version number. For
more, see [Module version numbering](/doc/modules/version-numbers).
In the following example, v1.1.0 is a minor release.
Old version: `v1.0.1`
New version: `v1.1.0`
You publish a minor release by tagging the module code in your repository,
incrementing the minor version number in the tag. For more, see [Publishing a
module](publishing).
## Publishing breaking API changes {#breaking}
You can publish a version that breaks backward compatibility by publishing a
_major_ version release.
A major version release doesn't guarantee backward compatibility, typically
because it includes changes to the module's public API that would break code
using the module's previous versions.
Given the disruptive effect a major version upgrade can have on code relying on
the module, you should avoid a major version update if you can. For more about
major version updates, see [Developing a major version update](/doc/modules/major-version).
For strategies to avoid making breaking changes, see the blog post [Keeping your
modules compatible](https://blog.golang.org/module-compatibility).
Where publishing other kinds of versions requires essentially tagging the module
code with the version number, publishing a major version update requires more
steps.
1. Before beginning development of the new major version, in your repository
create a place for the new version's source.
One way to do this is to create a new branch in your repository that is
specifically for the new major version and its subsequent minor and patch
versions. For more, see [Managing module source](/doc/modules/managing-source).
1. In the module's go.mod file, revise the module path to append the new major
version number, as in the following example:
```
example.com/mymodule/v2
```
Given that the module path is the module's identifier, this change
effectively creates a new module. It also changes the package path, ensuring
that developers won't unintentionally import a version that breaks their
code. Instead, those wanting to upgrade will explicitly replace occurrences
of the old path with the new one.
1. In your code, change any package paths where you're importing packages in
the module you're updating, including packages in the module you're updating.
You need to do this because you changed your module path.
1. As with any new release, you should publish pre-release versions to get
feedback and bug reports before publishing an official release.
1. Publish the new major version by tagging the module code in your repository,
incrementing the major version number in the tag -- such as from v1.5.2 to
v2.0.0.
For more, see [Publishing a module](/doc/modules/publishing).