HTTP Backend
You may install tools directly from HTTP URLs using the http backend. This backend downloads files from any HTTP/HTTPS URL and is ideal for tools that distribute pre-built binaries or archives through direct download links.
The code for this is inside of the mise repository at ./src/backend/http.rs.
Usage
The following installs a tool from a direct HTTP URL:
mise use -g http:my-tool[url=https://example.com/releases/my-tool-v1.0.0.tar.gz]@1.0.0The version will be set in ~/.config/mise/config.toml with the following format:
[tools]
"http:my-tool" = { version = "1.0.0", url = "https://example.com/releases/my-tool-v1.0.0.tar.gz" }Supported HTTP Syntax
- HTTP with URL parameter:
http:my-tool[url=https://example.com/releases/my-tool-v1.0.0.tar.gz]@1.0.0
Tool Options
The following tool-options are available for the http backend—these go in [tools] in mise.toml.
url (Required)
Specifies the HTTP URL to download the tool from. The URL supports templating with variables like version, os(), and arch():
[tools]
"http:my-tool" = { version = "1.0.0", url = "https://example.com/releases/my-tool-v{{version}}.tar.gz" }You can also use static URLs without templating:
[tools]
"http:my-tool" = { version = "1.0.0", url = "https://example.com/releases/my-tool-v1.0.0.tar.gz" }Template Variables
The following template functions are available in URLs (use double curly braces, e.g., version becomes {{version}}):
version- The tool versionos()- Operating system:macos,linux, orwindowsarch()- Architecture:x64orarm64os_family()- OS family:unixorwindows
The os() and arch() functions support remapping for tools that use different naming conventions:
[tools]
# HashiCorp tools use "darwin" instead of "macos" and "amd64" instead of "x64"
"http:sentinel" = {
version = "latest",
url = 'https://releases.hashicorp.com/sentinel/{{version}}/sentinel_{{version}}_{{os(macos="darwin")}}_{{arch(x64="amd64")}}.zip',
}This produces URLs like:
- macOS arm64:
sentinel_0.26.3_darwin_arm64.zip - macOS x64:
sentinel_0.26.3_darwin_amd64.zip - Linux x64:
sentinel_0.26.3_linux_amd64.zip
Platform-specific URLs
For tools that need different downloads per platform, use the table format:
[tools."http:my-tool"]
version = "1.0.0"
[tools."http:my-tool".platforms]
macos-x64 = { url = "https://example.com/releases/my-tool-v1.0.0-macos-x64.tar.gz" }
macos-arm64 = { url = "https://example.com/releases/my-tool-v1.0.0-macos-arm64.tar.gz" }
linux-x64 = { url = "https://example.com/releases/my-tool-v1.0.0-linux-x64.tar.gz" }TIP
You can use either macos or darwin, and x64 or amd64 for platform keys. macos and x64 are preferred in documentation and examples, but all variants are accepted.
OS/architecture values use mise's conventions: linux, macos, windows for operating systems and x64, arm64 for architectures. For platform-specific URLs, use the appropriate platform key (e.g., macos-x64, linux-arm64) and specify the full URL for each platform.
If you mess up and use something like darwin-aarch64 mise will try to figure out what you meant and do the right thing anyhow.
checksum
Verify the downloaded file with a checksum:
[tools."http:my-tool"]
version = "1.0.0"
url = "https://example.com/releases/my-tool-v1.0.0.tar.gz"
checksum = "sha256:a1b2c3d4e5f6789..."Instead of specifying the checksum here, you can use mise.lock to manage checksums.
Platform-specific Checksums
[tools."http:my-tool"]
version = "1.0.0"
[tools."http:my-tool".platforms]
macos-x64 = {
url = "https://example.com/releases/my-tool-v1.0.0-macos-x64.tar.gz",
checksum = "sha256:a1b2c3d4e5f6789...",
}
macos-arm64 = {
url = "https://example.com/releases/my-tool-v1.0.0-macos-arm64.tar.gz",
checksum = "sha256:b2c3d4e5f6789...",
}
linux-x64 = {
url = "https://example.com/releases/my-tool-v1.0.0-linux-x64.tar.gz",
checksum = "sha256:c3d4e5f6789...",
}checksum_url
URL of a published checksum source. When set, mise lock resolves checksums for every target platform — including platforms other than the one you are running on — without downloading the artifacts. This lets a single machine produce a complete, cross-platform lockfile.
checksum_url is a template (supports {{ version }}, {{ os() }}, {{ arch() }} and is platform-specific via platforms.<key>.checksum_url). It may point at any of:
- an individual checksum file (e.g.
<artifact>.sha256), which may contain just the hash or<hash> <filename>; - a SHASUMS-style file listing
<hash> <filename>for many platforms (the row is matched by the artifact's filename); - a manifest (e.g. JSON), combined with
checksum_exprbelow.
For individual and SHASUMS checksum files, the algorithm is detected from the file's name (*.sha512, SHA512SUMS, *.md5, *.b3, defaulting to sha256).
# Individual checksum file (one per artifact)
[tools."http:my-tool"]
version = "1.0.0"
url = "https://example.com/releases/my-tool-{{ version }}-{{ os() }}-{{ arch() }}.tar.gz"
checksum_url = "https://example.com/releases/my-tool-{{ version }}-{{ os() }}-{{ arch() }}.tar.gz.sha256"
# SHASUMS (one file lists every platform)
[tools."http:other-tool"]
version = "1.0.0"
url = 'https://example.com/{{ version }}/other_{{ version }}_{{ os(macos="darwin") }}_{{ arch(x64="amd64") }}.zip'
checksum_url = 'https://example.com/{{ version }}/other_{{ version }}_SHASUMS'checksum_expr
When the checksum lives in a manifest (rather than a plain checksum file), use checksum_expr to extract it. The manifest body fetched from checksum_url is evaluated with expr-lang. The following variables are available: body (the raw manifest), version, os, arch, url (the resolved artifact URL for the target), and filename.
The expression must evaluate to a qualified algo:hash string (e.g. sha256:<hash>, sha512:<hash>). Build the prefix in the expression: prepend a literal when the algorithm is fixed ("sha256:" + entry.hash), or read it from the manifest when it varies (entry.algo + ":" + entry.hash).
[tools."http:my-tool"]
version = "1.10.0"
checksum_url = "https://example.com/versions.json"
# Match the file whose url equals the resolved artifact url, return sha256:<hash>
checksum_expr = '"sha256:" + filter(fromJSON(body)[version + ""].files, { #.url == url })[0].sha256'
[tools."http:my-tool".platforms]
linux-x64 = { url = "https://example.com/my-tool-{{ version }}-linux-x86_64.tar.gz" }
macos-arm64 = { url = "https://example.com/my-tool-{{ version }}-macos-arm64.tar.gz" }expr-lang gotchas
The predicate placeholder must be written as { #... } with a space after {, because {# is the Tera comment delimiter. To index a map by a runtime value, force evaluation with [version + ""] — a bare [version] is treated as the literal key "version".
size
Verify the downloaded file size:
[tools."http:my-tool"]
version = "1.0.0"
url = "https://example.com/releases/my-tool-v1.0.0.tar.gz"
size = "12345678"Platform-specific Size
You can specify different sizes for different platforms:
[tools."http:my-tool"]
version = "1.0.0"
[tools."http:my-tool".platforms]
macos-x64 = {
url = "https://example.com/releases/my-tool-v1.0.0-macos-x64.tar.gz",
size = "12345678",
}
macos-arm64 = {
url = "https://example.com/releases/my-tool-v1.0.0-macos-arm64.tar.gz",
size = "9876543",
}
linux-x64 = {
url = "https://example.com/releases/my-tool-v1.0.0-linux-x64.tar.gz",
size = "11111111",
}strip_components
Number of directory components to strip when extracting archives:
[tools."http:my-tool"]
version = "1.0.0"
url = "https://example.com/releases/my-tool-v1.0.0.tar.gz"
strip_components = 1INFO
If strip_components is not explicitly set, mise will automatically detect when to apply strip_components = 1. This happens when the extracted archive contains exactly one directory at the root level and no files. This is common with tools like ripgrep that package their binaries in a versioned directory (e.g., ripgrep-14.1.0-x86_64-unknown-linux-musl/rg). The auto-detection ensures the binary is placed directly in the install path where mise expects it.
bin
Rename the downloaded binary to a specific name. This is useful when downloading single binaries that have platform-specific names:
[tools."http:docker-compose"]
version = "2.29.1"
url = "https://github.com/docker/compose/releases/download/v{{ version }}/docker-compose-linux-x86_64"
bin = "docker-compose" # Rename from docker-compose-linux-x86_64 to docker-composeINFO
When downloading single binaries (not archives), mise automatically removes OS/arch suffixes from the filename. For example, docker-compose-linux-x86_64 becomes docker-compose automatically. Use the bin option only when you need a specific custom name.
rename_exe
Rename the executable inside an extracted archive to a specific name. This is useful when archives contain binaries with platform-specific names or when installing kubectl plugins that need specific naming:
[tools."http:openunison-cli"]
version = "1.0.0"
url = "https://nexus.tremolo.io/repository/openunison-cli/openunison-cli-v{{version}}-linux.zip"
rename_exe = "kubectl-openunison-cli" # Rename extracted binary for kubectl pluginThis works by searching for the first executable in the extracted directory (or bin_path if specified) and renaming it to the specified name.
To rename multiple binaries from one archive, use the table form — each key is a source name (an exact file name or a glob) and each value is the new name:
[tools."http:mytool"]
version = "1.0.0"
url = "https://example.com/mytool-v{{version}}-linux.zip"
rename_exe = { "mytool-*" = "mytool", "myhelper-*" = "myhelper" }TIP
Use bin for renaming single binary downloads, and rename_exe for renaming executables inside archives.
format
Explicitly specify the archive format when the URL lacks a file extension or has an incorrect extension:
[tools."http:my-tool"]
version = "1.0.0"
url = "https://example.com/releases/my-tool-v1.0.0"
format = "tar.xz" # Explicitly specify the formatINFO
If format is not specified, mise automatically detects the format from the final URL after HTTP redirects, falling back to the configured URL. This allows an extensionless download endpoint to redirect to an archive such as .tar.gz. An explicit format always takes precedence, so use it when neither URL has a useful extension or when you need to override the detected format.
Platform-specific Format
You can specify different formats for different platforms:
[tools."http:my-tool"]
version = "1.0.0"
[tools."http:my-tool".platforms]
macos-x64 = {
url = "https://example.com/releases/my-tool-v1.0.0-macos-x64",
format = "tar.xz",
}
linux-x64 = {
url = "https://example.com/releases/my-tool-v1.0.0-linux-x64",
format = "tar.gz",
}
windows-x64 = {
url = "https://example.com/releases/my-tool-v1.0.0-windows-x64",
format = "zip",
}version_list_url
Fetch available versions from a remote URL. This enables mise ls-remote to list available versions for HTTP-based tools:
[tools."http:my-tool"]
version = "1.0.0"
url = "https://example.com/releases/my-tool-v{{version}}.tar.gz"
version_list_url = "https://example.com/releases/versions.txt"The version list URL can return data in multiple formats:
- Plain text: A single version number (e.g.,
2.0.53) - Line-separated: One version per line
- JSON array of strings:
["1.0.0", "1.1.0", "2.0.0"] - JSON array of objects:
[{"version": "1.0.0"}, {"tag_name": "v2.0.0"}] - JSON object with versions array:
{"versions": ["1.0.0", "2.0.0"]}
Version prefixes like v are automatically stripped.
version_regex
Extract versions from the version list URL response using a regular expression:
[tools."http:my-tool"]
version = "1.0.0"
url = "https://example.com/releases/my-tool-v{{version}}.tar.gz"
version_list_url = "https://example.com/releases/"
version_regex = 'my-tool-v(\d+\.\d+\.\d+)\.tar\.gz'The first capturing group is used as the version. If no capturing group is present, the entire match is used.
version_json_path
Extract versions from JSON responses using a jq-like path expression:
[tools."http:my-tool"]
version = "1.0.0"
url = "https://example.com/releases/my-tool-v{{version}}.tar.gz"
version_list_url = "https://api.example.com/releases"
version_json_path = ".[].tag_name"Supported path expressions:
.- root value.[]- iterate over array elements.[].field- extract field from each array element.field- extract field from object.field[]- iterate over array in field.field.subfield- nested field access.data.versions[]- complex nested paths.[?field=value]- filter array elements where field equals value
Examples:
# GitHub releases API format
version_json_path = ".[].tag_name"
# Nested versions array
version_json_path = ".data.versions[]"
# Release info objects
version_json_path = ".releases[].info.version"
# Filter for stable releases only (e.g., Flutter)
version_json_path = ".releases[?channel=stable].version"The filter syntax [?field=value] allows filtering JSON arrays before extraction. This is useful for APIs that return multiple release channels (stable, beta, dev) and you only want specific ones.
version_expr
Extract versions using an expr-lang expression. This provides the most flexibility for complex version extraction logic:
[tools."http:my-tool"]
version = "latest"
url = "https://example.com/releases/my-tool-v{{ version }}.tar.gz"
version_list_url = "https://example.com/versions.txt"
version_expr = 'split(body, "\n")'The expression receives the HTTP response body as the body variable and should return an array of version strings.
Example expressions:
# Split newline-separated versions
version_expr = 'split(body, "\n")'
# Split and filter empty lines
version_expr = 'filter(split(body, "\n"), # != "")'
# Parse JSON and extract object keys (useful for HashiCorp-style JSON)
# e.g., {"versions": {"1.0.0": {}, "2.0.0": {}}}
version_expr = 'keys(fromJSON(body).versions)'The expr-lang library provides built-in functions including:
fromJSON(string): Parse a JSON string into a valuetoJSON(value): Convert a value to a JSON stringkeys(map): Get the keys of an object/map as an arrayvalues(map): Get the values of an object/map as an arraylen(value): Get the length of a string, array, or map
TIP
version_expr takes precedence over version_regex and version_json_path if multiple are specified. Use it when the other options aren't flexible enough for your use case.
bin_path
Specify the directory containing binaries within the extracted archive, or where to place the downloaded file. This supports templating with {{version}}:
[tools."http:my-tool"]
version = "1.0.0"
url = "https://example.com/releases/my-tool-v1.0.0.tar.gz"
bin_path = "my-tool-{{version}}/bin" # expands to my-tool-1.0.0/binBinary path lookup order:
- If
bin_pathis specified, use that directory - If
bin_pathis not set, look for abin/directory in the install path - If no
bin/directory exists, search subdirectories forbin/directories - If no
bin/directories are found, use the root of the extracted directory
Caching Behavior
The HTTP backend implements an intelligent caching system to optimize disk usage and installation speed:
Cache Location
For normal user installations, downloaded and extracted files are cached in $MISE_DATA_DIR/http-tarballs/ instead of being stored separately for each tool installation. By default:
- Linux:
~/.local/share/mise/http-tarballs/ - macOS:
~/.local/share/mise/http-tarballs/
Explicit mise install --system, mise install --shared, and mise install-into installations are extracted directly into their destination. They do not use this persistent extraction cache, so the resulting installation is self-contained and does not link to the installing user's home directory.
Cache Key Generation
Cache keys are generated based on the file content to ensure identical downloads are shared across tools:
- Blake3 hash of file content: When no checksum is provided, mise calculates a Blake3 hash of the downloaded file
- Extraction options:
strip_componentsis included in the cache key since it affects the extracted structure
Example cache directory structure:
~/.local/share/mise/http-tarballs/
├── 71f774faa03daf1a58cc3339f8c73e6557348c8e0a2f3fb8148cc26e26bad83f/
│ ├── bin/my-tool
│ └── metadata.json
└── 1c2af379bdf1fed266bc44b49271e2df5b0dafae09f1cc744b3505ec50c84719_strip_1/
├── my-tool
└── metadata.jsonSymlinked Installations
Normal user installations are symlinks to the cached extracted content:
~/.local/share/mise/installs/http-my-tool/1.0.0 → ~/.local/share/mise/http-tarballs/71f774...This approach provides several benefits:
- Space efficiency: Normal user installs share identical tarballs across tools
- Faster installations: Cache hits avoid re-downloading and re-extracting files
- Consistency: Identical file content always uses the same cache entry
System, shared, and install-into destinations contain real files rather than these symlinks. This avoids leaving hidden cache entries behind after an uninstall and keeps shared installations independent of a specific user's data directory.
Cache Metadata
Each cache entry includes a metadata.json file with information about the cached content:
{
"url": "https://example.com/releases/my-tool-v1.0.0.tar.gz",
"checksum": "sha256:a1b2c3d4e5f6789...",
"size": 1024000,
"extracted_at": 1703001234,
"platform": "macos-arm64"
}Cache Management
Normal HTTP installations store their cache in $MISE_DATA_DIR/http-tarballs/. It is intentionally outside MISE_CACHE_DIR, so mise cache clear does not remove content that installed symlinks still reference.
System, shared, and install-into destinations do not create a persistent HTTP extraction cache.