Skip to main content

Auto-Updates

Set up automatic updates for your Krema application with secure Ed25519 signature verification.

Overview

The Krema auto-updater provides:

  • Ed25519 signature verification for secure updates
  • Multi-platform manifest format (Tauri-compatible)
  • Platform-specific installation (macOS .tar.gz, Windows .exe/.msi, Linux AppImage)
  • Frontend API for checking, downloading, and installing updates
  • Build-time signing via environment variable for CI/CD pipelines

Quick Start

1. Generate a Signing Keypair

krema signer generate

This creates a krema-private.key file and prints the public key.

2. Configure krema.toml

[updater]
pubkey = "MCowBQYDK2VwAyEA..."
endpoints = ["https://releases.example.com/{{target}}/{{current_version}}"]
check_on_startup = true

3. Use the Frontend API

const result = await krema.updater.check();
if (result.updateAvailable) {
await krema.updater.download();
await krema.updater.installAndRestart();
}

4. Sign Your Builds

export KREMA_SIGNING_PRIVATE_KEY="$(cat krema-private.key)"
krema bundle --type dmg

Key Generation

Generate an Ed25519 keypair:

krema signer generate

Output:

[Krema Signer] Ed25519 keypair generated successfully!

Private key written to: /path/to/krema-private.key

Add this to your krema.toml:

[updater]
pubkey = "MCowBQYDK2VwAyEA..."

WARNING: Keep your private key secure!
- Do NOT commit it to version control
- Store it in a secure location or CI secret
- Set KREMA_SIGNING_PRIVATE_KEY env var for CI builds

Sign Files Manually

# Using a key file
krema signer sign target/bundle/macos/MyApp.dmg --key krema-private.key

# Using environment variable
export KREMA_SIGNING_PRIVATE_KEY="$(cat krema-private.key)"
krema signer sign target/bundle/macos/MyApp.dmg

This creates a .sig file alongside the artifact.

Configuration

Add an [updater] section to krema.toml:

[updater]
# Required: Ed25519 public key for signature verification
pubkey = "MCowBQYDK2VwAyEA..."

# Required: update server endpoints
endpoints = ["https://releases.example.com/{{target}}/{{current_version}}"]

# Optional: check on startup (default: true)
check_on_startup = true

# Optional: HTTP timeout in seconds (default: 30)
timeout = 30

Endpoint URL Variables

VariableExampleDescription
{{target}}darwin-aarch64OS + architecture
{{arch}}aarch64Architecture only
{{current_version}}1.0.0Current app version

Valid targets: darwin-aarch64, darwin-x86_64, windows-x86_64, linux-x86_64, linux-aarch64

Update Server

Your server must return JSON when a newer version is available, or 204 No Content when up to date.

{
"version": "1.1.0",
"notes": "Bug fixes and improvements",
"pub_date": "2024-01-15T10:30:00Z",
"platforms": {
"darwin-aarch64": {
"signature": "base64-ed25519-signature",
"url": "https://cdn.example.com/v1.1.0/MyApp-darwin-aarch64.tar.gz",
"size": 52428800
},
"darwin-x86_64": {
"signature": "base64-ed25519-signature",
"url": "https://cdn.example.com/v1.1.0/MyApp-darwin-x86_64.tar.gz"
},
"windows-x86_64": {
"signature": "base64-ed25519-signature",
"url": "https://cdn.example.com/v1.1.0/MyApp-Setup.exe"
},
"linux-x86_64": {
"signature": "base64-ed25519-signature",
"url": "https://cdn.example.com/v1.1.0/MyApp.AppImage"
}
}
}

Simple Manifest

{
"version": "1.1.0",
"downloadUrl": "https://cdn.example.com/v1.1.0/MyApp-Setup.exe",
"releaseNotes": "Bug fixes and improvements",
"signature": "base64-ed25519-signature"
}

Frontend API

Check for Updates

const result = await window.krema.invoke('updater:check');

if (result.updateAvailable) {
console.log('New version:', result.version);
console.log('Release notes:', result.notes);
}

Download Update

// Listen for progress events
window.krema.on('download-progress', (data) => {
console.log(`Downloaded: ${data.percent}%`);
});

await window.krema.invoke('updater:download');

Install Update

// Restart and install
await window.krema.invoke('updater:install');

Full Example

async function checkForUpdates() {
const result = await window.krema.invoke('updater:check');

if (!result.updateAvailable) {
console.log('App is up to date');
return;
}

// Show update dialog
const userWantsUpdate = await showUpdateDialog(result);

if (!userWantsUpdate) return;

// Download with progress
window.krema.on('download-progress', updateProgressBar);

try {
await window.krema.invoke('updater:download');
await window.krema.invoke('updater:install');
} catch (error) {
console.error('Update failed:', error);
}
}

CI/CD Integration

GitHub Actions Example

name: Build and Release

on:
push:
tags: ['v*']

jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-latest, windows-latest, ubuntu-latest]

steps:
- uses: actions/checkout@v4

- name: Set up Java
uses: actions/setup-java@v4
with:
java-version: '22'
distribution: 'temurin'

- name: Build and sign
env:
KREMA_SIGNING_PRIVATE_KEY: ${{ secrets.KREMA_SIGNING_KEY }}
run: krema bundle

- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: bundle-${{ matrix.os }}
path: target/bundle/*

Platform-Specific Notes

macOS

  • Updates delivered as .tar.gz containing the .app bundle
  • App is replaced atomically
  • Gatekeeper may require notarization for unsigned apps

Windows

  • Supports .exe installer with install modes: passive, basicUi, quiet
  • User may need to confirm UAC prompt

Linux

  • AppImage replacement (make executable after download)
  • Deb/RPM updates require package manager integration