A high-performance, multi-provider auto-updater and release notes proxy server for Tauri v2 applications. It allows you to securely distribute updates and release notes from private or public repositories across all major Git hosting platforms.
Supported platforms include GitHub (Cloud & Enterprise Server), GitLab (Cloud & Self-Managed), Gitea / Forgejo / Codeberg, GitVerse, GitFlic, Bitbucket Cloud, Azure DevOps, and OneDev.
It shields your access tokens from end-users, streams installer downloads, handles multi-channel releases (stable and prerelease), and serves markdown/MDX release notes.
- Multi-Provider Support: First-class support for GitHub, GitLab, Gitea, Forgejo, Codeberg, GitVerse, GitFlic, Bitbucket, Azure DevOps, and OneDev (including self-hosted/enterprise instances).
- Token Security: Hides credentials from client apps; end-users never see or need API tokens.
- Dynamic Updates: Natively compatible with
@tauri-apps/plugin-updaterv2 format. - Multi-Channel Releases: Segregates
stableandprerelease(beta/alpha) channels. - Flexible Channel Selection: Supports channel selection via HTTP header or query parameter, with well-defined priority.
- Binary Streaming: Efficiently proxies binary downloads (
.exe,.zip,.sig,.dmg, etc.) directly from release assets without memory bloat. - Static Manifest Support: Serves
latest.json,latest.stable.json, andlatest.prerelease.jsonmanifests from release assets (sorted strictly by SemVer 2.0) or directly from the repository with automated fallbacks. - Rich Release Notes System: Serves dedicated version release notes written in Markdown or MDX (
release-notes/<version>.mdx), with full YAML frontmatter parsing (title,date,tags), multi-language BCP 47 localization support, and automatic fallbacks to provider release notes when needed. - Multi-Language Support (i18n): Serves localized release notes via
?lang=query parameter orX-App-Languageheader with BCP 47 tags (e.g.1.3.1.pt-BR.mdx,1.3.1.pt.mdx) and configurable fallback chains (FALLBACK_LANGUAGE). - Full Customization: Configurable manifest resolution strategy (
MANIFEST_SOURCE), target repository branch (REPO_BRANCH), manifests folder (MANIFESTS_DIR), release notes folder (RELEASE_NOTES_DIR), and fallback language (FALLBACK_LANGUAGE).
GET /update/:target/:versionPrimary endpoint for the Tauri updater client.
- Route Parameters:
:target— Target platform identifier (e.g.windows-x86_64,windows-aarch64,darwin-aarch64,linux-x86_64).:version— Currently installed client version (e.g.1.3.1,1.4.0-beta.1).
- Channel Selection: via
?channel=query parameter orX-Update-Channelheader. - Responses:
204 No Content: The client is already running the latest version.200 OK: A new version is available. Returns Tauri-compliant update metadata with direct download links pointing to/download?asset_id=....
GET /download?asset_id=:idSecurely proxies the release binary asset download from the Git provider.
- Query Parameters:
asset_id— Provider release asset identifier.
- Response:
- Streams or redirects to the file with
Content-Type: application/octet-streamand properContent-Disposition.
- Streams or redirects to the file with
GET /latest.json
GET /latest.:channel.jsonServes static release manifests (latest.json, latest.stable.json, latest.prerelease.json) according to the MANIFEST_SOURCE strategy:
-
auto(default): Searches for the manifest asset among published releases sorted descending by SemVer 2.0 (picking the highest version regardless of publication date, preventing hotfixes on older branches from downgrading clients). If not found in releases, automatically falls back to the repository under<MANIFESTS_DIR>. -
releases: Strictly searches among release assets. -
repo: Strictly searches repository files under<MANIFESTS_DIR>(defaults to the repository root). -
Channel Selection: via filename (e.g.
/latest.prerelease.json),?channel=query parameter, orX-Update-Channelheader. -
Fallback: If a channel-specific file is not present in the release or repository, automatically falls back to
latest.json.
GET /release-notes/:version
GET /changelogs/:version (alias for backward compatibility)Fetches the release notes for a specific version, with full multi-language (i18n) localization support.
- Route Parameters:
:version— Version string (e.g.1.3.1,v1.3.1,1.4.0-beta.1).
- Language / Locale Selection:
?lang=query parameter (highest priority, e.g.?lang=pt-BR,?lang=ru,?lang=en).X-App-LanguageHTTP header (e.g.X-App-Language: pt-BR).- If neither is provided, falls back to the configured
FALLBACK_LANGUAGE(oren).
- File Structure & Layouts (
RELEASE_NOTES_DIR_STRUCTURE): Release notes are placed in<RELEASE_NOTES_DIR>(defaults torelease-notes/) using BCP 47 language tags across two supported directory structures:- Nested subfolders (
nested):<RELEASE_NOTES_DIR>/<locale>/<version>.mdxor.md- e.g.
release-notes/pt-BR/1.3.1.mdx,release-notes/pt/1.3.1.mdx,release-notes/en/1.3.1.mdx
- e.g.
- Flat files (
flat):<RELEASE_NOTES_DIR>/<version>.<locale>.mdxor.mdand base<version>.mdx- e.g.
release-notes/1.3.1.pt-BR.mdx,release-notes/1.3.1.pt.mdx,release-notes/1.3.1.mdx
- e.g.
- Nested subfolders (
- Resolution & Fallback Strategy:
- Configurable via
RELEASE_NOTES_DIR_STRUCTURE:auto(default): Searches nested subfolders first across the locale fallback chain. If no localized file is found in nested folders, falls back to flat files across the same fallback chain, and finally the base<version>.mdxfile.nested: Searches strictly inside nested subfolders (<locale>/<version>.mdx).flat: Searches strictly among flat files (<version>.<locale>.mdxand<version>.mdx).
- Locale fallback chain example (when client requests
pt-BRandFALLBACK_LANGUAGE=en-US):pt-BR(client regional locale)pt(client base language)en-US(configured fallback locale)en(configured/default base fallback)
- If no matching file is found in the repository, falls back to the body of the corresponding provider release/tag (
release.body). - Optimized for performance: executes exactly 1 network request to list repository files and matches candidates in-memory.
- Configurable via
- Response Example:
{ "version": "1.3.1", "locale": "pt-BR", "releasedAt": "2026-09-21T18:23:25Z", "tags": ["feature", "fix"], "notes": "Full markdown content with frontmatter stripped" }
GET /release-notes
GET /changelogs (alias for backward compatibility)Returns an array of all available versions that have release notes files in <RELEASE_NOTES_DIR>.
- Channel Selection: Pass
?channel=stableor headerX-Update-Channel: stableto filter out pre-release versions. - Response Example:
(Sorted descending according to SemVer 2.0).
{ "versions": ["1.4.0-beta.2", "1.4.0-beta.1", "1.3.1", "1.3.0"] }
Channel names are fully arbitrary strings (e.g. stable, prerelease, alpha, beta, nightly, canary, preview, dev) and are not restricted to a fixed set:
stable(reserved keyword, default): Exclusively serves official, non-prerelease releases. Any release marked as draft or pre-release is filtered out.- Any other channel name (e.g.
prerelease,alpha,beta,nightly,canary, etc.):- In
/update/:target/:version: Activates pre-release eligibility, serving pre-release builds if newer than the client version. If a newer final stable release is published, pre-release clients also receive it. - In
/latest.json: Dynamically looks forlatest.<channel>.jsonin the repository (e.g.channel=nightlylooks forlatest.nightly.json,channel=alphalooks forlatest.alpha.json), automatically falling back tolatest.jsonif the channel file does not exist.
- In
When determining the release channel, the server applies the following priority order:
- Query Parameter (
?channel=...): Takes highest precedence. Useful for manual testing, browser links, and direct overrides. - HTTP Header (
X-Update-Channel: ...): Used by automated client libraries (like Tauri v2check({ headers })). - Default (
stable): Used when neither the query parameter nor the header is provided.
Pass the headers option to check() in @tauri-apps/plugin-updater:
import { check } from '@tauri-apps/plugin-updater';
// Check for stable updates (default)
const update = await check({
headers: {
'X-Update-Channel': 'stable',
},
});
// Check for pre-release / beta updates
const betaUpdate = await check({
headers: {
'X-Update-Channel': 'prerelease',
},
});Configure these variables in your deployment environment (e.g. Vercel Project Settings):
| Variable | Required | Default | Description |
|---|---|---|---|
GIT_PROVIDER |
No | github |
Git provider: github, gitlab, gitea, gitverse, gitflic, bitbucket, azure_devops, or onedev. |
GIT_TOKEN |
Yes | — | Personal Access Token with repository read access. |
REPO_OWNER |
Yes | — | Repository owner / group / organization. For Azure DevOps: org or org/project. |
REPO_NAME |
Yes | — | Repository / project name. |
GIT_API_URL |
No | — | Custom API Base URL for self-hosted instances (e.g. https://gitlab.mycompany.com/api/v4, https://github.corp.com/api/v3, https://codeberg.org/api/v1). Auto-detected if empty. |
REPO_BRANCH |
No | main |
Target repository branch for fetching manifests (latest*.json) and release notes. |
MANIFEST_SOURCE |
No | auto |
Manifest resolution strategy: auto (release assets first, fallback to repo), releases (only release assets), or repo (only repository files). |
MANIFESTS_DIR |
No | "" (root) |
Target directory in repository where release manifests (latest*.json) are located (used when served from repository). |
RELEASE_NOTES_DIR |
No | release-notes |
Target directory in repository where release notes (.md / .mdx) are located. |
RELEASE_NOTES_DIR_STRUCTURE |
No | auto |
Directory layout for release notes: auto (nested first, fallback to flat), nested, or flat. |
FALLBACK_LANGUAGE |
No | en |
Fallback language / locale when requested translation is unavailable (e.g. en, en-US, ru). |
GIT_PROVIDER=github
GIT_TOKEN=ghp_yourPersonalAccessTokenHere
REPO_OWNER=my-org
REPO_NAME=my-appFor GitHub Enterprise Server: set GIT_API_URL=https://github.mycompany.com/api/v3.
GIT_PROVIDER=gitlab
GIT_TOKEN=glpat-yourPersonalAccessTokenHere
REPO_OWNER=my-group
REPO_NAME=my-appFor GitLab Self-Managed: set GIT_API_URL=https://gitlab.mycompany.com/api/v4.
GIT_PROVIDER=gitea
GIT_TOKEN=your_gitea_token
REPO_OWNER=my-org
REPO_NAME=my-app
GIT_API_URL=https://codeberg.org/api/v1 # or https://gitea.mycompany.com/api/v1GIT_PROVIDER=gitverse
GIT_TOKEN=your_gitverse_token
REPO_OWNER=my-org
REPO_NAME=my-appPre-configured with https://gitverse.ru/api/v1.
GIT_PROVIDER=gitflic
GIT_TOKEN=your_gitflic_token
REPO_OWNER=my-alias
REPO_NAME=my-projectPre-configured with https://api.gitflic.ru (set GIT_API_URL for self-hosted GitFlic Enterprise).
GIT_PROVIDER=bitbucket
GIT_TOKEN=your_app_password_or_token # For Basic auth: username:app_password
REPO_OWNER=my-workspace
REPO_NAME=my-repoGIT_PROVIDER=azure_devops
GIT_TOKEN=your_azure_personal_access_token
REPO_OWNER=my-organization/my-project
REPO_NAME=my-repoGIT_PROVIDER=onedev
GIT_TOKEN=your_onedev_access_token
REPO_OWNER=my-group
REPO_NAME=my-project
GIT_API_URL=https://code.onedev.io/~api # or https://onedev.mycompany.com/~api- Create a Git repository (e.g.
tauri-proxy-updater) and push this project. - Log in to Vercel and click Add New -> Project.
- Select your repository, leave Framework Preset as Other, and click Deploy.
- In the Vercel Dashboard, go to Settings -> Environment Variables and add your provider configuration (e.g.
GIT_PROVIDER,GIT_TOKEN,REPO_OWNER,REPO_NAME). - Redeploy the latest deployment to apply the environment variables.
In your Tauri project's tauri.conf.json, specify your proxy endpoint:
"plugins": {
"updater": {
"pubkey": "<your-tauri-pubkey>",
"endpoints": [
"https://your-proxy.vercel.app/update/{{target}}-{{arch}}/{{current_version}}"
]
}
}