Config
These are the reference docs for configuring dist. dist init manages the most important of these for you, but if you ever need advanced configuration, this is where to look!
Configuration is currently read from the following sources, in increasing preference:
- Your language-specific project manifests like Cargo.toml or package.json
- Your workspace dist config in dist-workspace.toml or dist.toml
- Your package dist config in dist.toml
We're currently in the middle of a major config migration. For existing Rust users, all references to the [dist]
section in dist-workspace.toml and dist.toml may also refer to [workspace.metadata.dist]
or [package.metadata.dist]
in your Cargo.toml.
installers
install-libraries
bin-aliases
- shell and powershell installer settings
- npm installer settings
- homebrew installer settings
ci
build-local-artifacts
cache-builds
dispatch-releases
fail-fast
merge-tasks
pr-run-mode
tag-namespace
- github ci settings
- custom ci jobs
name
version
description
authors
repository
homepage
documentation
changelog
readme
license
license-files
binaries
cstaticlibs
cdylibs
build-command
the [dist]
section
This section represents all the configuration for how dist should build and publish your applications. The [dist]
section is a temporary placeholder which will soon be replaced (and automatically migrated) to a new hierarchy in Config 1.0.
allow-dirty
since 0.3.0
global-only default =[]
in your dist-workspace.toml or dist.toml:
[dist] allow-dirty = ["ci", "msi"]
This is a list of generate
tasks for dist to ignore when checking if generated configuration is up to date.
We recommend avoiding setting this, as it prevents dist from updating these files for you whenever you update or change your configuration. If you think you need this, please do file an issue or ask us about it, so we know what settings we're missing that necessitates this (or ideally, can point you to the existing settings).
Nevertheless, setting can be necessary for users who customize their own configuration beyond dist's generated defaults and want to avoid dist overwriting it.
Possible values are:
- "ci": don't check/regenerate ci scripts (release.yml)
- "msi": don't check/regenerate msi templates (main.wxs)
cargo-dist-version
since 0.3.0
global-only default =<none>
(this is mandatory!)in your dist-workspace.toml or dist.toml:
[dist] cargo-dist-version = "0.10.0"
This is added automatically by dist init
, and is a recording of its own version for the sake of reproducibility and documentation.
Your release CI will fetch and use the given version of dist to build and publish your project.
The syntax must be a valid Cargo-style SemVer Version (not a VersionReq!).
dist
since 0.3.0
package-local 📖 read the guide for this feature!
default =<none>
(infer it)in your dist-workspace.toml or dist.toml:
[dist] dist = true
Specifies whether dist should distribute (build and publish) a package, overriding all other rules for deciding if a package is eligible.
There are 3 major cases where you might use this:
dist = false
on a package can be used to force dist to ignore itdist = true
on a package can be used to force dist to distribute it in spite of signals like Cargo'spublish = false
that would suggest otherwise.dist = false
on a whole workspace defaults all packages to do-not-distribute, forcing you to manually allow-list packages withdist = true
(large monorepos often find this to be a better way of managing project distribution when most developers aren't release engineers).
targets
since 0.0.3
package-local 📖 read the guide for this feature!
default =<none>
in your dist-workspace.toml or dist.toml:
[dist] targets = [ "x86_64-pc-windows-msvc", "x86_64-unknown-linux-gnu", "x86_64-apple-darwin", "aarch64-apple-darwin", ]
This is a list of target platforms you want your packages to be built for.
The supported choices are:
- x64 macOS: "x86_64-apple-darwin"
- x64 Windows: "x86_64-pc-windows-msvc"
- x64 Linux: "x86_64-unknown-linux-gnu"
- arm64 macOS (Apple silicon): "aarch64-apple-darwin"
- arm64 Linux: "aarch64-unknown-linux-gnu"
- x64 Linux (static musl): "x86_64-unknown-linux-musl"
- arm64 Linux (static musl): "aarch64-unknown-linux-musl"
By default all runs of dist
will be trying to handle all platforms specified here at once. If you specify --target=...
on the CLI this will focus the run to only those platforms. As discussed in concepts, this cannot be used to specify platforms that are not listed in metadata.dist
, to ensure different runs agree on the maximum set of platforms.
artifact settings
Artifacts are the files that will be uploaded to your hosting. These settings affect what files those are, and what they contain. See also installers which are important enough to be separated out from other artifacts.
checksum
since 0.1.0
global-only 📖 read the checksum guide!
default ="sha256"
in your dist-workspace.toml or dist.toml:
[dist] checksum = "sha512"
Specifies how to checksum other artifacts. Supported values:
- "sha256" - generate a .sha256 file for each archive
- "sha512" - generate a .sha512 file for each archive
- "sha3-256" - generate a .sha3-256 file for each archive
- "sha3-512" - generate a .sha3-512 file for each archive
- "blake2s" - generate a .blake2s file for each archive
- "blake2b" - generate a .blake2b file for each archive
- "false" - do not generate any checksums
The hashes should match the result that sha256sum, sha512sum, etc. generate, and the file should be readable by those sorts of commands.
Future work is planned to support more robust signed checksums.
extra-artifacts
since 0.6.0
package-local 📖 read the artifacts guide!
default =<none>
in your dist-workspace.toml or dist.toml:
[[dist.extra-artifacts]] artifacts = ["schema.json"] build = ["cargo", "run", "--", "generate-schema"] [[dist.extra-artifacts]] artifacts = ["target/coolsignature.txt", "target/importantfile.xml"] build = ["make"]
(Note the [[double-square-brackets]]
, you can specify multiple extra-artifacts entries!)
This specifies extra artifacts to build and upload to your hosting. Users can download these directly alongside other artifacts like archives or installers.
Each extra-artifacts entry takes the following settings:
build
: A command or script to run to produce these artifacts. This is an array of one or more strings; the first string is the command to run, and any subsequent strings are arguments to pass to that command.artifacts
: An array of relative paths to files that dist expects to exist after thebuild
command is run. Every file in this list will be uploaded individually to your release as its own artifact.
dist uses this feature to distribute its dist-manifest-schema.json
as part of every release.
source-tarball
since 0.14.0
global-only 📖 read the artifacts guide!
default =true
in your dist-workspace.toml or dist.toml:
[dist] source-tarball = false
By default, dist creates and uploads source tarballs from your repository. This setting disables that behaviour. This is especially useful for users who distribute closed-source software to hosts outside their git repos and who would prefer not to distribute source code to their users.
ssldotcom-windows-sign
since 0.14.0
global-only 📖 read the windows signing guide!
default =<none>
(disabled)in your dist-workspace.toml or dist.toml:
[dist] ssldotcom-windows-sign = "prod"
If you wish to sign your Windows artifacts (EXEs and MSIs) such that Windows SmartScreen won't complain about them, this is the feature for you.
This setting takes one of two values:
- "prod": use the production ssl.com signing service
- "test": use the testing ("sandbox") ssl.com signing service
These strings match the environment_name setting that SSL.com's code signing action uses uses.
archive settings
auto-includes
since 0.0.3
package-local 📖 read the archives guide!
default =true
in your dist-workspace.toml or dist.toml:
[dist] auto-includes = false
Specifies whether dist should auto-include README, (UN)LICENSE, and CHANGELOG/RELEASES files in archives and installers.
See also: include
include
since 0.0.3
package-local 📖 read the archives guide!
default =[]
in your dist-workspace.toml or dist.toml:
[dist] include = [ "my-cool-file.txt", "../other-cool-file.txt", "./some/dir/" ]
This is a list of additional files or directories to copy into the root of all archives and installers. Paths are relative to the config file. Globs are not supported.
All items specified will be placed in the root of the archive/installer (so in the above example my-cool-file.txt
, other-cool-file.txt
, and dir
would be side-by-side with your binaries in an archive).
See also: auto-includes
package-libraries
since 0.20.0
package-local 🔧 this is an experimental feature!
📖 read the archives guide!
default =[]
in your dist-workspace.toml or dist.toml:
[dist] package-libraries = ["cdylib", "cstaticlib"]
Which kinds of compiled libraries to include in archives. By default only binaries will be included in archives and used to decide if a package should be distributed. This feature allows you to opt into bundling static and dynamic libraries that your package builds.
When enabled, libraries will be included in your archives alongside your binaries, but installers will still ignore them. That can be changed using the install-libraries
setting.
unix-archive
since 0.0.5
package-local 📖 read the archives guide!
default =".tar.xz"
in your dist-workspace.toml or dist.toml:
[dist] unix-archive = ".tar.gz"
Specifies the file format to use for archives that target not-windows.
See windows-archive for a complete list of supported values.
windows-archive
since 0.0.5
package-local 📖 read the archives guide!
default =".zip"
in your dist-workspace.toml or dist.toml:
[dist] windows-archive = ".tar.gz"
Allows you to specify the file format to use for archives that target windows.
Supported values:
- ".zip"
- ".tar.gz"
- ".tar.xz"
- ".tar.zstd" (deprecated for Zstd)
- ".tar.zst" (recommended for Zstd)
See also: unix-archive
build settings
These settings configure your builds.
dependencies
since 0.4.0
package-local 📖 read the guide for this feature!
default =<none>
in your dist-workspace.toml or dist.toml:
[dist.dependencies.homebrew] cmake = '*' libcue = { stage = ["build", "run"] } [dist.dependencies.apt] cmake = '*' libcue-dev = { version = "2.2.1-2" } [dist.dependencies.chocolatey] lftp = '*' cmake = { version = '3.27.6', targets = ["aarch64-pc-windows-msvc"] }
Allows specifying dependencies to be installed from a system package manager before the build begins. This is useful if your tool needs certain build tools (say, cmake) or links against C libraries provided by the package manager. This is specified in a Cargo-like format. Dependencies can be specified in two forms:
- A simple form, in which only a version is specified. If any version will do, use
'*'
. - A complex form, in several extra options can be specified.
Supported options are:
version
- A specific version of the package to install. This must be specified in the format that the package manager itself uses. Not used on Homebrew, since Homebrew does not support any method to specify installing specific versions of software.stage
- When exactly dist should make use of this package. Two values are supported:build
, which specifies that the package should be installed before the build occurs; andrun
, which specifies that the package should be installed alongside your software at the time end users run it. The default isbuild
. Ifrun
is specified for Homebrew dependencies, and you've enabled the Homebrew installer, the Homebrew installer will specify those packages as dependencies.targets
- A set of one or more targets to install the package on, in Rust target-triple format. If not specified, the package is installed on all targets. This is meant as an override to allow a package to be conditionally installed on only certain platforms; for example, a platform may need a build dependency only on Apple Silicon macOS, or have different build dependencies between x86_64 and ARM Windows.
Supported package managers:
- Apt (Linux)
- Chocolatey (Windows)
- Homebrew (macOS)
cargo build settings
These settings are specific to how we build your Cargo projects.
all-features
since 0.2.0
package-local 📖 read the Cargo project guide!
default =false
in your dist-workspace.toml or dist.toml:
[dist] all-features = true
Specifies that all features for a Cargo package should be enabled when building it (when set to true this tells us to pass --all-features
to Cargo).
default-features
since 0.2.0
package-local 📖 read the Cargo project guide!
default =true
in your dist-workspace.toml or dist.toml:
[dist] default-features = false
Specifies that default features for a Cargo package should be enabled when building it (when set to false, this tells us to pass --no-default-features
to Cargo).
features
since 0.2.0
package-local 📖 read the Cargo project guide!
default =[]
in your dist-workspace.toml or dist.toml:
[dist] features = ["serde-support", "fancy-output"]
Specifies feature-flags that should be passed to a Cargo package when building it. This lets you enable features that should be on "in production" but for whatever reason shouldn't be on by default.
For instance for packages that are a library and a CLI binary, some developers prefer to make the library the default and the CLI opt-in. In such a case you would want to add features = ["cli"]
to your config.
min-glibc-version
since 0.26.0
package-local default ={}
in your dist-workspace.toml or dist.toml:
[dist.min-glibc-version] # Override glibc version for specific target triplets aarch64-unknown-linux-gnu = "2.19" x86_64-unknown-linux-gnu = "2.18" # Override all remaining glibc versions. "*" = "2.17"
By default, dist will try to auto-detect the glibc version for each build for targets using glibc.
This setting allows you to override the minimum supported glibc version for specific target triplets, in case dist gets it wrong.
The special-cased "*"
key will allow you to override the minimum supported glibc version for all targets that are not individually overridden.
Note that this setting only affects builds for Linux targets using the GNU libc (glibc). Non-Linux targets, or targets using another libc are not affected.
msvc-crt-static
since 0.4.0
global-only 📖 read the Cargo project guide!
default =true
in your dist-workspace.toml or dist.toml:
[dist] msvc-crt-static = false
Specifies how The C Runtime (CRT) should be linked when building a Cargo package for Windows. Rust defaults to this being = false
(dynamically link the CRT), but dist actually defaults to making this = true
(statically link the CRT). The Rust default is mostly a historical accident, and it's widely regarded to be an error that should one day be changed. Specifically it's a mistake for the typical Rust application which statically links everything else, because Windows doesn't actually guarantee that the desired things are installed on all machines by default, and statically linking the CRT is a supported solution to this issue.
However when you do want a Rust application that dynamically links more things, it then becomes correct to dynamically link the CRT so that your app and the DLLs it uses can agree on things like malloc. However Rust's default is still insufficient for reliably shipping such a binary, because you really should also bundle a "Visual C(++) Redistributable" with your app that installs your required version of the CRT. The only case where it's probably fine to not do this is when shipping tools for programmers who probably already have all of that stuff installed (i.e. anyone who installs the Rust toolchain will have that stuff installed).
This config exists as a blunt way to return to the default Rust behaviour of dynamically linking the CRT if you really want it, but more work is needed to handle Redistributables for that usecase.
See this issue for details and discussion.
precise-builds
since 0.1.0
global-only 📖 read the Cargo project guide!
default =false
in your dist-workspace.toml or dist.toml:
[dist] precise-builds = true
Build only the required Cargo packages, and individually.
See "inferring precise-builds" for the default behaviour.
By default when we need to build anything in your workspace, we try to build your entire workspace with --workspace
. This setting tells dist to instead build each app individually.
On balance, the Rust experts we've consulted with find building with --workspace to be a safer/better default, as it provides some of the benefits of a more manual workspace-hack, without the user needing to be aware that this is a thing.
TL;DR: cargo prefers building one copy of each dependency in a build, so if two apps in your workspace depend on e.g. serde with different features, building with --workspace, will build serde once with the features unioned together. However if you build each package individually it will more precisely build two copies of serde with different feature sets.
The downside of using --workspace is that if your workspace has lots of example/test crates, or if you release only parts of your workspace at a time, we build a lot of gunk that's not needed, and potentially bloat up your app with unnecessary features.
If that downside is big enough for you, this setting is a good idea.
inferring precise-builds
Although dist prefers --workspace
builds (precise-builds = false
) for the reasons stated above, it will attempt to check if that's possible, and use --package
builds if necessary (precise-builds = true
).
If you explicitly set precise-builds = false
and we determine --package
builds are required, dist will produce an error. precise-builds = true
will never produce an error.
Precise-builds are considered required when you use any of features, all-features, or default-features and not all of the packages in your workspace have the same values set.
So for instance if you have several packages in your workspace and only one sets all-features = true
, then we will require precise-builds, and will pass --all-features
to only the cargo build
for that package.
If we instead set all-features = true
on the workspace, then we will just pass --all-features
to cargo build --workspace
.
rust-toolchain-version
since 0.0.3
global-only ⚠️ deprecated in 0.1.0
📖 read the Cargo project guide!
default =<none>
in your dist-workspace.toml or dist.toml:
[dist] rust-toolchain-version = "1.67.1"
Deprecation reason: rust-toolchain.toml is a more standard/universal mechanism for pinning toolchain versions for reproducibility. Teams without dedicated release engineers will likely benefit from unpinning their toolchain and letting the underlying CI vendor silently update them to "some recent stable toolchain", as they will get updates/improvements and are unlikely to have regressions.
This represents the "ideal" Rust toolchain to build your Cargo packages with. This is in contrast to the builtin Cargo rust-version which is used to specify the minimum supported Rust version. Your CI scripts will install that version of the Rust toolchain with rustup.
The syntax must be a valid rustup toolchain like "1.60.0" or "stable" (should not specify the platform, we want to install this toolchain on all platforms).
Without this setting, CI won't explicitly setup a toolchain, so whatever's on the machine will be used (with things like rust-toolchain.toml behaving as normal).
cargo-auditable
since 0.26.0
package-local default =false
in your dist-workspace.toml or dist.toml:
[dist] cargo-auditable = true
Specifies whether to use cargo auditable
to embed metadata about your dependency tree into the built executables.
When this value is false, dist will run cargo build
; when it is true, dist will run cargo auditable build
.
You can then use cargo audit
to audit your dependencies for security vulnerabilities that have been reported to the RustSec Vulnerability Database.
cargo-cyclonedx
since 0.26.0
package-local default =false
in your dist-workspace.toml or dist.toml:
[dist] cargo-cyclonedx = true
Specifies whether to use cargo cyclonedx
to generate and upload a Software Bill Of Materials (SBOM) for each project in a workspace.
omnibor
since 0.26.0
package-local default =false
in your dist-workspace.toml or dist.toml:
[dist] omnibor = true
Specifies whether to use omnibor-cli
to generate and upload OmniBOR Artifact IDs for artifact in a release.
installer settings
Installers main installer docs!
installers
since 0.0.3
package-local 📖 read the installer guides!
default =[]
in your dist-workspace.toml or dist.toml:
[dist] installers = [ "shell", "powershell", "npm", "homebrew", "msi" ]
This is a list of installers you want for your packages.
Possible values:
- "shell": a curl-sh script for unixy systems
- "powershell": an irm-iex script for Windows
- "npm": an npm package that runs prebuilt binaries
- "homebrew": a Homebrew formula
- "msi": a Windows MSI installer
bin-aliases
since 0.14.0
package-local 📖 read the guide for this feature!
default =<none>
in your dist-workspace.toml or dist.toml:
[dist.bin-aliases] mybin = ["somealias"] myotherbin = ["someotheralias", "anotheralias"]
This is a map of binary names to aliases that your installers should create for those binaries. These aliases aren't included in your archives, and are only created by the installers themselves. The way the alias is created is installer-specific, and may change in the future. Currently:
- shell: symlink
- powershell: hardlink
- npm: extra "bins" pointing at the same command
- homebrew: bin.install_symlink
- msi: not currently supported
install-libraries
since 0.20.0
package-local 🔧 this is an experimental feature!
📖 read the guide for this feature!
default =[]
in your dist-workspace.toml or dist.toml:
[dist] install-libraries = ["cdylib", "cstaticlib"]
To use this feature, you must also enable the package-libraries setting.
Which kinds of compiled libraries to unpack and installer with your installers. When enabled, libraries will be installed alongside a package's binaries.
When using shell and powershell installers The currently-supported install-paths will place libraries alongside binaries. This means they may appear in the user's $PATH
, which you may find undesirable, and we may change it.
shell and powershell installer settings
These settings are specific to the shell and powershell installers, which provide a curl | sh
installer for unix, and the equivalent irm | iex
for windows. The two largely support the same things and behave the same, and typically want to be configured and enabled together.
custom-success-msg
since 0.15.0
package-local 📖 read the shell and powershell installer guides!
default ="everything's installed!"
in your dist-workspace.toml or dist.toml:
[dist] custom-success-msg = "axolotlsay is ready to rumble! >o_o<"
The message to display on success in the shell and powershell installers.
install-path
since 0.1.0
package-local 📖 read the shell and powershell installer guides!
default ="CARGO_HOME"
*in your dist-workspace.toml or dist.toml:*s
[dist] install-path = "~/.my-app/"
[dist] install-path = ["$MY_APP_HOME/bin", "~/.my-app/bin"]
The strategy that script installers (shell, powershell) should use for selecting a path to install things at, with 3 possible syntaxes:
-
"CARGO_HOME": installs as if
cargo install
did it (tries$CARGO_HOME/bin/
, but if$CARGO_HOME
isn't set uses$HOME/.cargo/bin/
). Note that we do not (yet) properly update some of the extra metadata files Cargo maintains, so Cargo may be confused if you ask it to manage the binary. -
"~/some/subdir/": installs to the given subdir of the user's
$HOME
-
"$SOME_VAR/some/subdir": installs to the given subdir of the dir defined by
$SOME_VAR
NOTE:
$HOME/some/subdir
is technically valid syntax but it won't behave the way you want on Windows, because$HOME
isn't a proper environment variable. Let us handle those details for you and just use~/subdir/
.
All of these error out if none of the required env-vars are set to a non-empty value. Since 0.14.0 you can provide an array of options to try if all the previous ones fail. Such an "install-path cascade" would typically be used to provide an environment variable for changing the install dir, with a more hardcoded home subdir as a fallback:
install-path = ["$MY_APP_HOME/bin", "~/.my-app/bin"]
It hasn't yet been tested whether this is appropriate to pair with things like $XDG_BIN_HOME
, but we'd sure like it to be.
We do not currently sanitize/escape the path components (it's not really a security concern when the user is about to download+run an opaque binary anyway). In the future validation/escaping of this input will become more strict. We do appear to correctly handle spaces in paths on both windows and unix (i.e. ~/My dist Documents/bin/
works), but we won't be surprised if things misbehave on Interesting Inputs.
Future Improvements:
- In the future we may support XDG dirs
- In the future we may support %windows dirs%
- For historical reasons
CARGO_HOME
uses a slightly different install dir structure from the others, and so for safety cannot be paired with the others strategies in an install-path cascade.
(Please file an issue if you have other requirements!)
install-updater
since 0.12.0
global-only 📖 read the updater guide!
default =false
in your dist-workspace.toml or dist.toml:
[dist] install-updater = true
Determines whether to install a standalone updater program alongside your program when using the shell or powershell installers. This program will be named yourpackage-update
, and can be run by the user to automatically check for newer versions and install them without needing to visit your website.
Users who received your package from a package manager, such as Homebrew or npm, will need to use the same package manager to perform upgrades.
This updater is the commandline tool contained in the open source axoupdater package.
npm installer settings
These settings are specific to the npm installer.
npm-scope
since 0.0.6
package-local 📖 read the npm installer guide!
default =<none>
in your dist-workspace.toml or dist.toml:
[dist] npm-scope = "@axodotdev"
Specifies that npm installers should be published under the given scope. The leading @
is mandatory. If you newly enable the npm installer in dist init
's interactive UI, then it will give you an opportunity to add the scope.
If no scope is specified the package will be global.
See also: npm-package
npm-package
since 0.14.0
package-local 📖 read the npm installer guide!
default = package.namein your dist-workspace.toml or dist.toml:
[dist] npm-package = "mycoolapp"
Specifies that an npm installer should be published under the given name, as opposed to the name of the package they are defined by.
This does not set the scope the package is published under, for that see npm-scope.
homebrew installer settings
These settings are specific to the homebrew installer.
tap
since 0.2.0
global-only 📖 read the homebrew installer guide!
default =<none>
in your dist-workspace.toml or dist.toml:
[dist] tap = "axodotdev/homebrew-tap"
This is the name of a GitHub repository which dist should publish the Homebrew installer to. It must already exist, and the token which creates releases must have write access.
It's conventional for the repo name to start with homebrew-
.
formula
since 0.11.0
package-local 📖 read the homebrew installer guide!
default = package.namein your dist-workspace.toml or dist.toml:
[dist] formula = "axolotlbrew"
Specifies the Homebrew formula name for a package, as opposed to the package's name.
This works well specifically for folks who are customizing their bin name and would like the Homebrew formula to match the bin name as opposed to the package name.
publisher settings
These settings are specific to how we publish your packages to package managers like homebrew taps and npm.
publish-prereleases
since 0.2.0
global-only default =false
in your dist-workspace.toml or dist.toml:
[dist] publish-preleases = true
If you set publish-prereleases = true
, dist will publish prerelease versions to package managers such as homebrew and npm. By default, dist will only publish stable versions to avoid polluting your releases. This is especially important for things like Homebrew which don't really have a proper notion of "prereleases" or "literally having more than one published version of a package".
hosting settings
These settings govern how we host your files with platforms like GitHub Releases and axo Releases, and the text we tell them to display about your releases.
hosting
since 0.5.0
global-only 📖 read the releases guide!
default =<none>
(infer based on ci)in your dist-workspace.toml or dist.toml:
[dist] hosting = ["axodotdev", "github"]
Possible values:
axodotdev
: Use axo Releases (currently in closed beta)github
: Use GitHub Releases (default if ci = "github")
Specifies what hosting provider to use when hosting/announcing new releases.
By default we will automatically use the native hosting of your CI provider, so when running on GitHub CI, we'll default to using GitHub Releases for hosting/announcing.
If axo Releases and GitHub Releases are both enabled, we will host/announce on both platforms, but the GitHub Release's contents will regard the axo Release as the canonical source for the files. Specifically if you have a shell installer, the GitHub Release will contain a shell installer that fetches from axo Releases and it will tell you to curl | sh
with a URL to axo Releases.
(Ideally files uploaded to both hosts should be bitwise identical, which means we have to "pick" a host to win for fetching installers, and if you're using axo Releases at all you probably want that one to win.)
display
since 0.16.0
package-local 📖 read the releases guide!
default =true
in your dist-workspace.toml or dist.toml:
[dist] display = false
Specifies whether this package should be displayed in release bodies of hosting providers (like GitHub Releases). This is useful for hiding things that aren't the "primary" or "featured" application but still need to be included in the release for logistical reasons.
display-name
since 0.16.0
package-local 📖 read the releases guide!
default = package.namein your dist-workspace.toml or dist.toml:
[dist] display-name = "my cool app"
Specifies how to refer to the package in release bodies of hosting providers (like GitHub Releases). This is useful for situations where the package name must have a certain value for logistical reasons but you want to refer to it by a nicer name in marketing materials.
force-latest
since 0.16.0
global-only 📖 read the releases guide!
default =false
in your dist-workspace.toml or dist.toml:
[dist] force-latest = true
Overrides dist's default handling of prerelease versions. Ordinarily, dist uses semver rules to determine if a version number is a prerelease or not and has some special handling if it is. With this setting, dist will always consider a version to be the latest no matter what its version number is.
This means that the following prerelease handling behaviour will no longer apply:
- If dist interprets a version as a prerelease, it will publish it to GitHub Releases as a "prerelease" instead of the "latest" release.
- dist will not publish prereleases to Homebrew or npm by default.
See also: publish-prereleases
github hosting settings
These settings govern how we host your files on GitHub Releases and the text we tell them to display.
github-attestations
since 0.16.0
global-only 🔧 this is an experimental feature!
📖 read the guide for this feature!
default =false
in your dist-workspace.toml or dist.toml:
[dist] github-attestations = true
If you're using GitHub Releases, this will enable GitHub's experimental artifact attestation feature.
github-release
since 0.17.0
global-only 📖 read the releases guide!
default = "auto"in your dist-workspace.toml or dist.toml:
[dist] github-release = "announce"
Possible values:
auto
: create the GitHub Release whenever is besthost
: create the GitHub Release during the host stepannounce
: create the GitHub Release during the announce step
Controls which stage of the release process the GitHub Release will be created in.
By default, the GitHub Release is created during the "host" phase, as it hosts the files some installers will try to download. If axo Releases is also enabled, it will be moved back to the "announce" phase, as the files will be primarily hosted on axo Releases, and GitHub Releases will be treated like a backup and announcement of the release.
Most users should be well-served by the default setting, and changing it is likely to introduce undesirable publishing race conditions. The only reason you might want to override this setting is if you're using dispatch-releases = true
and you really want your git tag to be the last operation in your release process (because creating a GitHub Release necessarily creates the git tag if it doesn't yet exist). In this case setting github-release = "announce" will accomplish that, but see below for what race conditions this might introduce.
If using only GitHub Releases, and you force it to run during "announce", there will be a very brief window (~30 seconds) during which generated Homebrew and npm installers are live and referencing URLs that will only exist when the GitHub Release is created, causing the packages to error out when installed.
However, if you're publishing only packages that don't reference hosted artifacts (such as Cargo crates, or any custom publish job that fully embeds the binaries), then there is no race, and you could consider changing the default. That said, it would be a looming footgun if you ever introduce new publish jobs and forget about this.
github-releases-repo
since 0.14.0
global-only 📖 read the releases guide!
default =<none>
(use the project's own repository)in your dist-workspace.toml or dist.toml:
[dist] github-releases-repo = "myorg/public"
Allows specifying a different repo to publish GitHub Releases to than the current one. This can be used to publish to a public repo from a private one. Let's assume you want to publish to myorg/public
from myorg/private
. Then in your config in myorg/private
, you'd set github-releases-repo = "myorg/public"
.
To ensure the workflow has permission to do this, you need to create a GitHub Personal Access Token with the "repo" scope that can access myorg/public
. This must be added as a GitHub SECRET called GH_RELEASES_TOKEN
on myorg/private
.
GitHub Releases isn't really designed for this, so there's a few strange things that will happen here:
-
GitHub Releases always requires a commit to be tagged, and in this case the tag would be on
myorg/public
even though the workflow is running onmyorg/private
, which (presumably) has unrelated commits. Currently we will tag the latest commit on the default branch ofmyorg/public
. If you're using the dispatch-releases flow, no tag will be created onmyorg/private
. -
GitHub Releases will provide a source tarball pointing at the tagged commit on
myorg/public
, but that's (presumably) not the source that your release was actually built from. This cannot be disabled, but it's also essentially harmless. However dist uploads its own source tarball and that WILL contain the source of the private repo. If you don't want this, use thesource-tarball = false
setting.
github-releases-submodule-path
since 0.15.0
global-only 📖 read the releases guide!
default =<none>
(use the project's root repository)in your dist-workspace.toml or dist.toml:
[dist] github-releases-submodule-path = "rel/path/to/submodule"
Designed for use with github-releases-repo setting. When specified, the cached commit of the submodule at this path will be used as the commit to tag in the target repository. If not specified, the latest commit in the target repository will be used instead.
create-release
since 0.2.0
global-only 📖 read the releases guide!
default =true
in your dist-workspace.toml or dist.toml:
[dist] create-release = false
Whether we should create the GitHub Release for you in your Release CI.
If true, dist will create a new GitHub Release and generate a title/body for it based on your changelog.
If false, dist will assume a draft GitHub Release for the current git tag already exists with the title/body you want, and just upload artifacts to it, undrafting when all artifacts are uploaded.
See also: github-release
ci settings
These settings govern how your CI should work, including how to trigger the release process and custom tasks to run.
ci
since 0.0.3
global-only 📖 read the ci customization guide!
default =[]
in your dist-workspace.toml or dist.toml:
[dist] ci = ["github"]
This is a list of CI backends you want to support, allowing dist to know what CI scripts to generate. Most dist features require this to be enabled!
"github" is currently the only supported CI backend.
build-local-artifacts
since 0.8.0
global-only 📖 read the ci customization guide!
default =true
in your dist-workspace.toml or dist.toml:
[dist] build-local-artifacts = false
build-local-artifacts = false
disables the builtin CI jobs that would build your binaries and archives (and MSI installers). This allows a Sufficiently Motivated user to use custom build-local-jobs
to completely replace dist's binary building with something like maturin.
The requirements are simply that you need your custom actions to:
- build archives (tarballs/zips) and checksums that the local CI was expected to produce
- use the github upload-artifacts action to upload all of those to an artifact named
artifacts
You can get a listing of the exact artifact names to use and their expected contents with:
dist manifest --artifacts=local --no-local-paths
([checksum]
entries are separate artifacts and not actually stored in the archives.)
Also note that for legacy reasons a tarball is expected to have all the contents nested under a root dir with the same name as the tarball (sans extension), while zips are expected to have all the files directly in the root (installers pass --strip-components=1
to tar when extracting).
cache-builds
since 0.18.0
global-only 📖 read the ci customization guide!
default =<none>
(inferred, probablyfalse
)in your dist-workspace.toml or dist.toml:
[dist] cache-builds = true
Determines whether CI will try to cache work between builds. Defaults false, unless release-branch
or pr-run-mode = "upload"
are enabled.
This is unlikely to be productive because for safety the cache aggressively invalidates based on things like "Cargo.toml or Cargo.lock changed" (which is always true if you change the version of a Rust project), and a noop cache run can randomly take over 2 minutes (typically more like 10 seconds).
The cases where we enable it by default are the only ones we know where you might want to enable it.
dispatch-releases
since 0.8.0
global-only 📖 read the ci customization guide!
default =false
in your dist-workspace.toml or dist.toml:
[dist] dispatch-releases = true
When enabled, your release CI is triggered with workflow_dispatch instead of tag-push (relying on creating a GitHub release implicitly tagging).
Enabling this disables tag-push releases, but keeps pr checks enabled.
By default the workflow dispatch form will have "dry-run" populated as the tag, which is taken to have the same meaning as pr-run-mode = "upload"
: run the plan and build steps, but not the publish or announce ones. Currently hosting is also disabled, but future versions may add some forms of hosting in this mode.
fail-fast
since 0.1.0
global-only 📖 read the ci customization guide!
default =false
in your dist-workspace.toml or dist.toml:
[dist] fail-fast = true
Whether failing builds tasks should make us give up on all other build tasks.
When building a release in CI, you might discover that one platform's build is broken. When this happens you have two options: kill all other builds immediately (fail-fast = true
), or keep trying to build all the other platforms anyway (fail-fast = false
) to see what other platforms might have problems.
Either way, the global build task will refuse to run if any of these tasks fail, so you can't get any kind of partial release. However, if the build failure was spurious, resuming all failed tasks should resume without issue.
pr-run-mode
since 0.3.0
global-only 📖 read the ci customization guide!
default ="plan"
in your dist-workspace.toml or dist.toml:
[dist] pr-run-mode = "upload"
This setting determines to what extent we run your Release CI on pull-requests:
- "skip": don't check the release process in PRs
- "plan": run 'dist plan' on PRs (recommended, also the default)
- "upload": build and upload an artifacts to the PR (expensive)
tag-namespace
since 0.10.0
global-only 📖 read the ci customization guide!
default =<none>
in your dist-workspace.toml or dist.toml:
[dist] tag-namespace = "some-prefix"
Setting tag-namespace = "owo"
will change the tag matching expression we put in your GitHub CI, to require the tag to start with "owo" for dist to care about it. This can be useful for situations where you have several things with different tag/release workflows in the same workspace. It also renames release.yaml
to owo-release.yml
to make it clear it's just one of many release workflows.
NOTE: if you change tag-namespace, dist will generate the new owo-release.yml
file, but not delete the old one. Be sure to manually delete the old release.yml
!
merge-tasks
since 0.1.0
global-only 📖 read the ci customization guide!
default =false
in your dist-workspace.toml or dist.toml:
[dist] merge-tasks = true
Whether we should try to merge otherwise-parallelizable tasks onto the same machine, sacrificing latency and fault-isolation for the sake of minor efficiency gains.
For example, if you build for x64 macos and arm64 macos, by default we will generate ci which builds those independently on separate logical machines. With this enabled we will build both of those platforms together on the same machine, making it take twice as long as any other build and making it impossible for only one of them to succeed.
The default is false
. Before 0.1.0 it was always true
and couldn't be changed, making releases annoyingly slow (and technically less fault-isolated). This setting was added to allow you to restore the old behaviour, if you really want.
github ci settings
These settings are specific to your dist GitHub CI.
github-build-setup
since 0.20.0
global-only 🔧 this is an experimental feature!
📖 read the ci customization guide!
default =<none>
in your dist-workspace.toml or dist.toml:
[dist] github-build-setup = "path/to/build-setup.yml"
This configuration value should be a path relative to the repository your .github/workflows
directory.
The file located at that path should contain a yaml array of steps which will be
performed before we call dist build
.
github-custom-job-permissions
since 0.18.0
global-only 📖 read the ci customization guide!
default =<none>
in your dist-workspace.toml or dist.toml:
[dist] publish-jobs = ["npm", "./my-custom-publish"] github-custom-job-permissions = { "my-custom-publish" = { packages = "admin" } }
Allows you to customize the permissions given to your custom CI jobs.
By default all custom publish-jobs
get { id-token = "write", packages = "write" }
.
If you override a publish job's permissions, the default permissions will be removed.
All other custom jobs default to no special permissions.
github-custom-runners
since 0.6.0
global-only 📖 read the ci customization guide!
default =<none>
in your dist-workspace.toml or dist.toml:
[dist.github-custom-runners] aarch64-unknown-linux-gnu = "buildjet-8vcpu-ubuntu-2204-arm" aarch64-unknown-linux-musl = "buildjet-8vcpu-ubuntu-2204-arm"
Allows specifying which runner to use for a target. The keys within this table are target triples in the same format as the "targets" setting. Any targets not specified in this table will use the defaults.
In addition to defining runners for a target, it's also possible to specify a runner for the global, non-target-specific tasks using the global
key. This runner will be used for tasks like plan
, host
, generating installers, and so on.
custom ci jobs
These settings all similarly extend your dist GitHub CI with custom jobs to run at specific steps of the release process, which looks like:
- plan: check settings, decide what we're releasing
- build-local: compile things for each platform
- build-global: combine things and generate installers
- host: upload files to hosting, make URLs live
- publish: publish to package managers
- announce: announce to the world that the release was a success
plan-jobs
since 0.7.0
global-only 📖 read the ci customization guide!
default =[]
in your dist-workspace.toml or dist.toml:
[dist] plan-jobs = ["./my-job"]
This setting determines which custom jobs to run during the "plan" phase, which happens at the very start of the build.
local-artifacts-jobs
since 0.7.0
global-only 📖 read the ci customization guide!
default =[]
in your dist-workspace.toml or dist.toml:
[dist] local-artifacts-jobs = ["./my-job"]
This setting determines which custom jobs to run during the "build local artifacts" phase, during which binaries are built.
global-artifacts-jobs
since 0.7.0
global-only 📖 read the ci customization guide!
default =[]
in your dist-workspace.toml or dist.toml:
[dist] global-artifacts-jobs = ["./my-job"]
This setting determines which custom jobs to run during the "build global artifacts" phase, during which installers are built.
host-jobs
since 0.7.0
global-only 📖 read the ci customization guide!
default =[]
in your dist-workspace.toml or dist.toml:
[dist] host-jobs = ["./my-job"]
This setting determines which custom jobs to run during the "host" phase, during which dist decides whether to proceed with publishing the release.
publish-jobs
since 0.2.0
global-only 📖 read the ci customization guide!
default =[]
in your dist-workspace.toml or dist.toml:
[dist] publish-jobs = ["homebrew", "npm", "./my-custom-job"]
This setting determines which publish jobs to run. It accepts 3 kinds of value:
- "homebrew", for builtin homebrew publishes (since 0.2.0)
- "npm", for builtin npm publishes (since 0.14.0)
- "./my-custom-job" for custom jobs (since 0.3.0)
post-announce-jobs
since 0.7.0
global-only 📖 read the ci customization guide!
default =[]
in your dist-workspace.toml or dist.toml:
[dist] post-announce-jobs = ["./my-job"]
This setting determines which custom jobs to run after the "announce" phase. "Announce" is the final phase during which dist schedules any jobs, so any custom jobs specified here are guaranteed to run after everything else.
the [workspace]
section
This section is only available in dist-workspace.toml
files.
workspace.members
since 0.20.0
global-only 📖 read the project structure guide!
default =[]
in your dist-workspace.toml or dist.toml:
[workspace] members = [ "cargo:rel/path/to/rust/workspace", "npm:some/js/project/", "npm:some/other/js/project/", "dist:a/generic/project/" ]
In a dist-workspace.toml, this specifies the various projects/workspaces/packages that should
be managed by dist. Each member is of the format <project-type>:<relative-path>
where
relative-path
is a path relative to the dist-workspace.toml to a directory containing that type of project, and project-type
can be one of:
- cargo: expect a Cargo.toml for a cargo-based Rust project in that dir
- npm: expect a package.json for an npm-based JavaScript project in that dir
- dist: expect a dist.toml for a dist-based generic project in that dir
the [package]
section
This section is available in dist.toml
and dist-workspace.toml
files.
package.name
since 0.12.0
package-only 📖 read the project structure guide!
default =<none>
in your dist-workspace.toml or dist.toml:
[package] name = "my-cool-app"
The name of the package.
All packages must have a name, either sourced from a dist.toml or inherited from a language's native package format like a Cargo.toml, package.json, etc.
The name is used in a myriad of places to refer to your application and its releases.
package.version
since 0.12.0
package-only 📖 read the project structure guide!
default =<none>
in your dist-workspace.toml or dist.toml:
[package] version = "1.2.0-prerelease.2"
The version of the package. Syntax must be a valid Cargo SemVer Version.
All packages must have a version, either sourced from a dist.toml or inherited from a language's native package format like a Cargo.toml, package.json, etc.
The version is used in a myriad of places to refer to your application and its releases.
package.description
since 0.12.0
package-only 📖 read the project structure guide!
default =<none>
in your dist-workspace.toml or dist.toml:
[package] version = "A cool application that solves all your problems!"
A brief description of the package.
If not specified, this can be inherited from a language's native package format like a Cargo.toml, package.json, etc.
This may be used in the metadata of various installers.
package.authors
since 0.12.0
package-only 📖 read the project structure guide!
default =<none>
in your dist-workspace.toml or dist.toml:
[package] authors = ["axodotdev <[email protected]>"]
The authors of the package.
If not specified, this can be inherited from a language's native package format like a Cargo.toml, package.json, etc.
This may be used in the metadata of various installers. We recommend keeping it fairly generic to avoid needless hassles from people changing their names.
package.repository
since 0.12.0
package-only 📖 read the project structure guide!
default =<none>
in your dist-workspace.toml or dist.toml:
[package] repository = "https://github.com/axodotdev/axolotolsay"
A URL to the repository hosting this package.
The following formats are all supported and treated as equivalent:
"https://github.com/axodotdev/axolotolsay"
"https://github.com/axodotdev/axolotolsay.git"
"[email protected]:axodotdev/axolotlsay.git"
If not specified, this can be inherited from a language's native package format like a Cargo.toml, package.json, etc.
This is essentially required as almost all dist features are blocked behind knowing where your project is hosted. All distable packages must agree on this value.
package.homepage
since 0.12.0
package-only 📖 read the project structure guide!
default =<none>
in your dist-workspace.toml or dist.toml:
[package] homepage = "https://opensource.axo.dev/axolotlsay"
A URL to the homepage of the package.
If not specified, this can be inherited from a language's native package format like a Cargo.toml, package.json, etc.
This may be used in the metadata of various installers.
package.documentation
since 0.12.0
package-only 📖 read the project structure guide!
default =<none>
in your dist-workspace.toml or dist.toml:
[package] documentation = "https://docs.rs/axolotlsay"
A URL to the documentation of the package.
If not specified, this can be inherited from a language's native package format like a Cargo.toml, package.json, etc.
This may be used in the metadata of various installers.
package.changelog
since 0.12.0
package-only 📖 read the project structure guide!
default =<none>
in your dist-workspace.toml or dist.toml:
[package] changelog = "../CHANGELOG.md"
A relative path to the changelog file for your package.
If not specified, this can be inherited from a language's native package format like a Cargo.toml, package.json, etc.
This can be used by various dist features that use your changelog, such as auto-includes and release-bodies. We will often autodetect this for you, so this setting is only needed if your changelog has a special name/location/format we can't find.
package.readme
since 0.12.0
package-only 📖 read the project structure guide!
default =<none>
in your dist-workspace.toml or dist.toml:
[package] readme = "../README.md"
A relative path to the readme file for your package.
If not specified, this can be inherited from a language's native package format like a Cargo.toml, package.json, etc.
This can be used by various dist features that use your readme, such as auto-includes. We will often autodetect this for you, so this setting is only needed if your readme has a special name/location/format we can't find.
package.license
since 0.12.0
package-only 📖 read the project structure guide!
default =<none>
in your dist-workspace.toml or dist.toml:
[package] license = "MIT OR Apache-2.0"
The license(s) of your package, in SPDX format.
If not specified, this can be inherited from a language's native package format like a Cargo.toml, package.json, etc.
This may be used in the metadata of various installers.
package.license-files
since 0.12.0
package-only 📖 read the project structure guide!
default =<none>
in your dist-workspace.toml or dist.toml:
[package] readme = ["../LICENSE-MIT", "../LICENSE-APACHE"]
Relative paths to the license files for your package.
If not specified, this can be inherited from a language's native package format like a Cargo.toml, package.json, etc.
This can be used by various dist features that use your license files, such as auto-includes. We will often autodetect this for you, so this setting is only needed if your licenses have a special name/location/format we can't find.
package.binaries
since 0.12.0
package-only 📖 read the project structure guide!
default =<none>
in your dist-workspace.toml or dist.toml:
[package] binaries = ["my-app", "my-other-app"]
Names of binaries (without the extension) your package is expected to build and distribute.
If not specified, this can be inherited from a language's native package format like a Cargo.toml, package.json, etc.
Including binaries by default opts your package into being distable.
See also: bin-aliases, cstaticlibs, cdylibs
package.cstaticlibs
since 0.12.0
package-only 📖 read the project structure guide!
default =<none>
in your dist-workspace.toml or dist.toml:
[package] cstaticlibs = ["mystaticlib", "some-helper"]
Names of c-style static libraries (without the extension) your package is expected to build and distribute.
If not specified, this can be inherited from a language's native package format like a Cargo.toml, package.json, etc.
Including cstaticlibs opts your package into being distable if package-libraries = ["cstaticlibs"]
is set.
package.cdylibs
since 0.12.0
package-only 📖 read the project structure guide!
default =<none>
in your dist-workspace.toml or dist.toml:
[package] cdylibs = ["mydylib", "some-other-helper"]
Names of c-style dynamic libraries (without the extension) your package is expected to build and distribute.
If not specified, this can be inherited from a language's native package format like a Cargo.toml, package.json, etc.
Including cdylibs opts your package into being distable if package-libraries = ["cdylibs"]
is set.
See also: binaries, cstaticlibs
package.build-command
since 0.12.0
package-only 🔧 this is an experimental feature!
📖 read the project structure guide!
default =<none>
in your dist-workspace.toml or dist.toml:
[package] build-command = ["make", "dist"]
A command to run in your package's root directory to build its binaries, cstaticlibs, and cdylibs.
If not specified, this can be inherited from a language's native package format like a Cargo.toml, package.json, etc. (This is often preferred since we can natively understand e.g. Cargo builds).
setting availabilities
Throughout the above docs, different settings will have different rules for where they can be specified (root workspace config file or package config file), and how they'll be inherited.
- global-only: this setting can only be set in the root workspace config (dist-workspace.toml or dist.toml)
- package-only: this setting can only be set in a package config (dist.toml)
- package-local: this setting can be set in either, with the package overriding the workspace value if it provides one (and otherwise inheriting it).
When you override a package-local setting, the workspace value will be discarded completely. So for instance if the workspace sets features = ["feature1", "feature2"]
and a package sets features = ["feature2", "feature3"]
, then that package will only get feature2 and feature3.