Quanto pesa davvero un'app desktop web, e perché la risposta cambia
Se devi consegnare un'app desktop costruita con tecnologie web, la scelta fra Tauri 2 ed Electron parte quasi sempre dal peso del download. La risposta breve è che la differenza esiste ed è grande, perché Electron porta con sé un browser intero (Chromium) e Node.js, mentre Tauri usa la WebView che il sistema operativo ha già. Ma una percentuale fissa come «-90%» non regge: dipende dal formato in cui consegni l'app (installer, AppImage, installazione offline) e da quanto lavori sul profilo di compilazione. Qui trovi una misura che puoi rifare, i casi in cui il vantaggio si assottiglia e il prezzo che paghi in cambio, cioè una WebView diversa su ogni piattaforma.
Una precisazione su che cosa ho potuto provare. Sulla macchina su cui ho scritto non ci sono Rust né Cargo, quindi non ho
compilato nessuna app Tauri e non ho misurato installer di Tauri: le dimensioni di Tauri che leggi sono quelle dichiarate
dalla documentazione ufficiale, citate come tali. Ho eseguito lo script Python della prossima sezione, ho validato
tauri.conf.json contro lo schema ufficiale e ho letto la documentazione di Tauri 2 il 2026-11-13. Gli altri
listati sono schemi da adattare al tuo progetto. Questo è il primo articolo della serie e non richiede prerequisiti, se non
sapere che cosa sono un bundle JavaScript e un installer.
Che cosa c'è dentro un'app Electron, con numeri che puoi rifare
La documentazione di Electron lo dice in una riga: il framework funziona «embedding Chromium and Node.js into its binary».
Quindi il peso di partenza di qualunque app Electron è quello del runtime, prima ancora del tuo codice. Per misurarlo
senza scaricare un centinaio di megabyte basta chiedere a GitHub le dimensioni degli asset di una release: ogni asset ha un
campo size in byte.
import json
import urllib.request
TAG = "v45.3.1"
URL = f"https://api.github.com/repos/electron/electron/releases/tags/{TAG}"
WANTED = [
f"electron-{TAG}-linux-x64.zip",
f"electron-{TAG}-darwin-arm64.zip",
f"electron-{TAG}-win32-x64.zip",
]
request = urllib.request.Request(URL, headers={"User-Agent": "misura-dimensioni"})
with urllib.request.urlopen(request, timeout=30) as response:
release = json.load(response)
sizes = {asset["name"]: asset["size"] for asset in release["assets"]}
for name in WANTED:
megabytes = sizes[name] / 1_000_000
print(f"{name}: {sizes[name]} byte = {megabytes:.1f} MB")
# Output (v45.3.1, due esecuzioni identiche):
# electron-v45.3.1-linux-x64.zip: 123927956 byte = 123.9 MB
# electron-v45.3.1-darwin-arm64.zip: 121031836 byte = 121.0 MB
# electron-v45.3.1-win32-x64.zip: 158352921 byte = 158.4 MB
Lo script legge la release con il tag fissato v45.3.1 e non releases/latest: con «latest» l'uscita
cambierebbe a ogni nuova versione e non potresti confrontare due esecuzioni. L'intestazione User-Agent serve perché
l'API di GitHub rifiuta le richieste che non ne hanno uno. Il risultato è identico in due esecuzioni consecutive, consultato il
2026-11-13: da circa 121 MB (macOS Apple Silicon) a circa 158 MB (Windows x64), contando 1 MB come un milione di byte.
Leggi il numero con tre cautele. Sono archivi zip del runtime nudo, senza la tua app e senza l'installer che l'utente scarica davvero. Sono compressi, quindi lo spazio occupato sul disco dopo l'installazione è maggiore. E non dicono nulla su un'app finita, che dipende dallo strumento con cui impacchetti. Se qualcuno ti mostra «Electron 150 MB contro Tauri 10 MB» senza dire quale file ha pesato, sta confrontando formati diversi.
Che cosa c'è dentro un'app Tauri
L'architettura è descritta nella pagina «Process Model» della documentazione: ogni app ha un core process scritto in Rust, che è l'unico componente con accesso pieno al sistema operativo, e che avvia una o più finestre WebView. La libreria di WebView non è dentro il tuo eseguibile: è collegata dinamicamente a runtime. La pagina introduttiva ne trae la conseguenza che un'app Tauri minima può restare sotto i 600 KB. Quel numero descrive un'app piccola con pochi asset, non la tua.
Ecco il punto che i confronti saltano: il tuo frontend pesa quanto pesa, con Tauri come con Electron. Supponi, solo per ragionare e non come misura, un frontend Angular compilato da 3 MB. Quei 3 MB li porti in entrambi i casi, quello che cambia è tutto il resto. La differenza fra i due framework sta quindi nel runtime, cioè nei circa 120-160 MB misurati sopra contro la parte Rust del core, e non nell'interfaccia.
La parte Rust la controlli tu, e la leva più semplice è il profilo di rilascio in Cargo.toml. La pagina
«App Size» della documentazione propone questa configurazione per la toolchain stabile.
[profile.dev]
incremental = true
[profile.release]
codegen-units = 1 # lascia a LLVM più margine di ottimizzazione
lto = true # ottimizza anche attraverso i confini fra crate
opt-level = "s" # privilegia la dimensione; con 3 si privilegia la velocità
panic = "abort" # niente tabelle di unwinding
strip = true # toglie i simboli di debug dal binario
Riga per riga. opt-level = "s" chiede al compilatore di ottimizzare per la dimensione; con 3
ottimizzi la velocità, e la documentazione di Cargo avverte che i livelli "s" e "z" non producono
sempre binari più piccoli, quindi la prova è misurare. lto = true abilita le ottimizzazioni sull'intero grafo
delle dipendenze, al prezzo di un collegamento più lungo. codegen-units = 1 impedisce di spezzare il crate in
più unità: sono più lente da compilare ma ottimizzate meglio. strip = true toglie i simboli di debug, e quindi
anche la possibilità di leggere un crash report con nomi di funzione.
panic = "abort" è la riga che richiede una decisione. Con questa impostazione un panic termina il processo
invece di srotolare lo stack, e il codice che conta su catch_unwind per sopravvivere a un panic smette di
funzionare. In un'app desktop il caso tipico è un thread che va in panic: con abort si chiude tutta l'app. Se
preferisci una chiusura meno brutale, lascia il valore predefinito e accetta un binario un po' più grande, di cui puoi misurare lo scarto con i comandi dell'ultima sezione.
Togliere i comandi che non usi
Una seconda leva è nella configurazione. Dalle versioni tauri 2.4 e tauri-cli 2.4 esiste
l'opzione build.removeUnusedCommands, che elimina dal binario i comandi che nessun file di capability
autorizza. Il file seguente è un tauri.conf.json completo per un frontend che gira in sviluppo su
localhost:4200, come il server di sviluppo di Angular.
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "Appunti",
"version": "0.1.0",
"identifier": "dev.example.appunti",
"build": {
"devUrl": "http://localhost:4200",
"beforeDevCommand": "npm start",
"beforeBuildCommand": "npm run build",
"frontendDist": "../dist",
"removeUnusedCommands": true
},
"app": {
"windows": [{ "title": "Appunti", "width": 900, "height": 640 }],
"security": { "capabilities": ["main-capability"] }
},
"bundle": { "active": true, "targets": "all" }
}
Le chiavi devUrl e beforeDevCommand dicono a Tauri dove trovare il server di sviluppo e come
avviarlo; frontendDist è la cartella statica che finisce nell'app in produzione; identifier è
l'identificativo univoco dell'app, usato anche dalle firme. Ho validato questo file contro lo schema JSON ufficiale
(versione 2.12.5, scaricato da schema.tauri.app) con un validatore: risulta valido, mentre una copia con la
chiave scritta male (removeUnusedCommandz) viene rifiutata come proprietà non ammessa.
L'opzione ha due limiti scritti nella documentazione. Il beneficio si vede solo se nei file di capability elenchi i singoli
comandi invece di usare i permessi default, che ne abilitano molti. E non considera le ACL aggiunte a runtime,
quindi se le usi devi verificare a mano che il comando che ti serve non sia stato tolto.
Dove il confronto di peso diventa meno favorevole
Tre casi riducono il vantaggio, e tutti sono documentati. Il primo è la consegna come AppImage su Linux: la pagina dedicata avverte che il file cresce «from the 2-6 MB range to 70+ MB», perché l'AppImage porta con sé le dipendenze. Il secondo è Windows: se l'utente non ha già WebView2, l'installer deve procurarselo, e come lo fa cambia il peso.
| Modalità WebView2 | Serve rete? | Peso aggiunto all'installer |
|---|---|---|
downloadBootstrapper (predefinita) | Sì | 0 MB |
embedBootstrapper | Sì | circa 1,8 MB |
offlineInstaller | No | circa 127 MB |
fixedVersion | No | circa 180 MB |
La tabella (dalla pagina «Windows Installer») mostra il compromesso: l'installer piccolo presuppone una connessione, quello per ambienti offline incorpora un runtime che pesa quanto un intero Electron, circa 127 MB contro i 121-158 MB misurati sopra. Su Windows 10 dalla versione 1803 e su Windows 11 WebView2 è già nel sistema, quindi per la maggior parte degli utenti vale la riga a 0 MB. Il terzo caso sei tu: un'app con molte dipendenze Rust, o con asset pesanti, cresce a prescindere dal framework.
Il prezzo: una WebView diversa su ogni piattaforma
Non portare Chromium significa non decidere quale motore esegue la tua interfaccia. Su Windows Tauri usa WebView2, basata su Chromium e capace di aggiornarsi da sola. Su macOS usa WKWebView, parte del sistema e aggiornata con il sistema: le versioni di macOS non più supportate non ricevono aggiornamenti di WebKit. Su Linux usa webkit2gtk, e la versione dipende dalla distribuzione; la pagina «Webview Versions» dichiara che la propria tabella delle distribuzioni è molto incompleta. Con Electron, invece, il motore è quello che hai impacchettato: lo scegli tu e lo aggiorni tu a ogni release, il che toglie variabilità e ti lascia la responsabilità delle patch di sicurezza di Chromium.
In pratica la verifica che cambia è questa. Per ogni funzione CSS o API JavaScript che usi, controlla il supporto non solo in Chrome ma anche nel Safari corrispondente al WebKit del tuo macOS minimo e nella WebKitGTK della distribuzione Linux più vecchia che vuoi supportare. La documentazione di Tauri 2 indica Ubuntu 22.04 e Debian 12 come base di compilazione adatta, perché richiede WebKitGTK 4.1. Se un utente apre l'app e un elemento non si dispone come sul tuo portatile, la causa più probabile è il motore, non il tuo codice.
Sicurezza: le capability prendono il posto dell'allowlist
Il frontend gira nella WebView e può chiamare il core Rust solo tramite messaggi. In Tauri 1 i permessi stavano in una
sezione allowlist di tauri.conf.json; la guida di migrazione dice che in Tauri 2 è stata rimossa e
sostituita dal sistema di permessi e capability. Una capability è un file in src-tauri/capabilities che assegna
permessi a finestre precise.
{
"identifier": "main-capability",
"description": "Permessi della finestra principale",
"windows": ["main"],
"permissions": [
"core:window:default",
"core:window:allow-set-title",
"store:default"
]
}
Il file concede alla finestra con etichetta main i permessi di base sulle finestre, la modifica del titolo e le
operazioni predefinite del plugin store (che va installato a parte). Le etichette contano, non i titoli: la documentazione ricorda che i confini di
sicurezza si basano sulle etichette delle finestre. Elencare main-capability in
app.security.capabilities, come nel file di configurazione sopra, restringe l'app a quelle sole capability: senza
elenco sono attive tutte le capability presenti nella cartella.
Un dettaglio da non perdere: i comandi che registri tu con invoke_handler sono, per impostazione predefinita,
invocabili da tutte le finestre dell'app. Per restringerli devi elencarli in AppManifest::commands nello script
build.rs. Inoltre la documentazione elenca ciò da cui le capability non proteggono: codice Rust insicuro, scope troppo
larghi, vulnerabilità nella WebView di sistema, compromissione della catena di fornitura.
Se il tuo frontend è Angular
La pagina «Frontend Configuration» spiega che Tauri si comporta come un host di file statici: gli chiedi di servire una cartella di HTML, CSS e JavaScript, quindi vanno bene generazione statica, applicazioni a pagina singola o multipagina, e non è supportato il rendering lato server. Angular non compare fra i framework con una guida dedicata (ci sono Next.js, Nuxt, Qwik, SvelteKit, Vite, Leptos e Trunk), ma la stessa pagina dice che un framework non elencato può funzionare senza configurazione aggiuntiva.
Un'applicazione Angular compilata come SPA statica rientra in questo schema; un'applicazione che dipende dall'SSR, come questo sito, no. Non ho provato Angular dentro Tauri: è un'indicazione ricavata dalla documentazione, da verificare con un progetto di prova prima di pianificare una migrazione.
Come scegliere, con i compromessi
I criteri che spostano davvero la decisione sono pochi, e qui sono elencati senza una gerarchia fissa:
- Backend già scritto in Node: Electron incorpora Node.js, quindi il codice JavaScript del backend si riusa; in Tauri la logica nativa è Rust e i processi esterni passano dal plugin shell.
- Team senza esperienza di Rust: Tauri ha una curva d'ingresso reale, perché ogni funzione nativa è codice Rust.
- Rendering identico ovunque: con Electron il motore è sempre il tuo Chromium; con Tauri è quello del sistema.
- Download e spazio come vincolo: qui Tauri vince nettamente, entro i limiti della sezione precedente.
- App mobile dallo stesso progetto: Tauri 2 prevede Android e iOS, Electron è per Windows, macOS e Linux.
Nessun criterio decide da solo. Se il tuo problema è il peso, ma il team scrive Node da anni e il backend è già in JavaScript, il risparmio può non ripagare la riscrittura. Se invece nessuno dipende da Node e la banda dei tuoi utenti è il vero collo di bottiglia, lo stesso risparmio pesa più di tutto il resto. Per la maturità conta anche la data: Tauri 2.0 è stato annunciato stabile il 2 ottobre 2024, e al 2026-11-13 la versione stabile del crate è la 2.12.5, mentre la serie 3 è ancora in alpha.
Come misurare la tua app prima di decidere
Il confronto che serve a te non è fra due medie, è fra due build della tua app. Se hai un prototipo, compila e guarda cosa produce il bundler.
# dalla radice del progetto, dopo aver installato i prerequisiti di Tauri
npm run tauri build
du -sh src-tauri/target/release/bundle/*
ls -l src-tauri/target/release/appunti
Schema da adattare, non eseguito qui: il nome del binario (appunti) segue il productName del tuo progetto.
du -sh riporta la dimensione di ogni formato prodotto nella cartella bundle, mentre ls -l sul
binario ti dà il peso dell'eseguibile da solo. Confronta formati equivalenti (installer con installer, sulla stessa macchina) e riporta
sempre il formato accanto al numero: è l'unico modo per evitare un confronto che non regge.
Domande frequenti
Il «90% di bundle in meno» è un numero reale?
Non come valore fisso. Il runtime di Electron misura circa 121-158 MB compresso, e un'app Tauri minima può restare sotto i 600 KB secondo la documentazione, ma il rapporto fra due runtime non è il rapporto fra due installer. Dipende da formato di consegna, dipendenze Rust e asset, e la misura valida è quella fatta sulla tua app.
Posso usare Angular, React o Vue con Tauri?
Sì, purché il frontend si compili in file statici: Tauri non supporta il rendering lato server. React, Vue e Svelte rientrano nella guida per Vite, che la documentazione raccomanda per le SPA; Angular non ha una guida ufficiale e segue la checklist generale.
Tauri funziona anche su Android e iOS?
Sì, dalla versione 2.0 stabile del 2 ottobre 2024. Che cosa funzioni e che cosa no, plugin per plugin, lo trovi in Tauri mobile su Android e iOS: stato del supporto.
Come distribuisco gli aggiornamenti di un'app Tauri?
Con il plugin ufficiale updater, che richiede una coppia di chiavi dedicata e non è disponibile su mobile. La procedura, insieme alla firma del codice, è in Distribuzione su macOS, Windows e Linux.
Che cosa sai fare adesso
Sai che cosa pesa in un'app Electron e perché, e come rifare la misura dalle release pubblicate. Sai leggere un'affermazione
come «-90%» chiedendoti quale formato è stato pesato, e conosci i tre casi in cui il vantaggio di Tauri si riduce. Sai che la
WebView di sistema è il prezzo da pagare e dove si vede, come restringere i permessi con le capability, e quale configurazione
di Cargo e di tauri.conf.json prova a ridurre il binario. Il passo successivo è la comunicazione fra Rust e frontend,
nell'articolo
Tipi condivisi fra Rust e TypeScript; per l'ecosistema di estensioni vai a
I plugin di Tauri 2.
Fonti
- Tauri 2: What is Tauri? - il limite dichiarato di 600 KB per un'app minima e l'uso della WebView di sistema, consultata il 2026-11-13
- Tauri 2: Process Model - core process, WebView collegate dinamicamente, principio del minimo privilegio, consultata il 2026-11-13
- Tauri 2: App Size - profilo Cargo e opzione removeUnusedCommands con i requisiti di versione, consultata il 2026-11-13
- The Cargo Book: Profiles - significato di opt-level, lto, codegen-units, panic e strip, consultata il 2026-11-13
- Tauri 2: Webview Versions - WebView2, WKWebView e webkit2gtk, aggiornamenti e incompletezza della tabella Linux, consultata il 2026-11-13
- Tauri 2: Windows Installer - le modalità di installazione di WebView2 e il peso aggiunto, consultata il 2026-11-13
- Tauri 2: AppImage - crescita da 2-6 MB a oltre 70 MB e base di compilazione consigliata, consultata il 2026-11-13
- Tauri 2: Capabilities - struttura del file, permessi per finestra, comandi di default e limiti della protezione, consultata il 2026-11-13
- Tauri 2: Frontend Configuration - Tauri come host statico, assenza di supporto per l'SSR, elenco dei framework documentati, consultata il 2026-11-13
- Tauri 2.0 Stable Release - data del rilascio stabile (2 ottobre 2024) e supporto mobile, consultata il 2026-11-13
- Tauri 2: Upgrade from Tauri 1 - la rimozione di tauri.allowlist in favore dei permessi, consultata il 2026-11-13
- crates.io: tauri - versione stabile 2.12.5 e serie 3.0.0 in alpha, letti dall'API del registro il 2026-11-13
- Electron: Introduction - Chromium e Node.js incorporati nel binario, consultata il 2026-11-13
- GitHub REST API: Releases - l'elenco degli asset di una release con il campo size usato dallo script, consultata il 2026-11-13
Lo script Python è stato eseguito due volte con la stessa uscita; tauri.conf.json è stato validato contro lo schema JSON di Tauri 2.12.5 e il profilo Cargo è stato letto come TOML. Il resto dei listati è uno schema da adattare, non compilato: sulla macchina di scrittura non ci sono Rust né Cargo.

Commenti
Caricamento commenti...
Accedi per commentare