Back to Blog

Console Debugging in Tauri: DevTools & Terminal Logging

Sandy LaneSandy Lane

Video: Console Debugging in Tauri: DevTools & Terminal Logging by Taught by Celeste AI - AI Coding Coach

Take the quiz on the full lesson page
Test what you've read · interactive walkthrough

Two consoles. Browser DevTools for the frontend. The terminal you launched tauri dev in for Rust. Knowing which gets which output is half the debugging skill.

A Tauri app has two runtimes. The frontend runs in a webview — debug it like any web app, with browser DevTools. The Rust backend runs as a native process — debug it like any Rust app, with println!, eprintln!, and the tracing ecosystem. This lesson is the map of where each kind of output goes and how to read it.

DevTools for the frontend

In development, right-click anywhere in the Tauri window and pick Inspect Element. The familiar Chrome DevTools panel appears.

Useful tabs:

  • Consoleconsole.log output, errors, warnings.
  • Network — every HTTP request the frontend makes (via the http plugin or fetch).
  • Elements — the live HTML/CSS, identical to a browser.
  • Sources — set breakpoints in your TypeScript/JavaScript.
  • Application — local storage, cookies, IndexedDB.

DevTools are auto-enabled in tauri dev builds. For production builds, they're disabled by default. To enable in production:

"app": {
  "windows": [{
    "devTools": true
  }]
}

Or build with cargo run --features devtools.

Logging from JavaScript

console.log("info");
console.warn("watch out");
console.error("something went wrong");
console.table([{ a: 1 }, { a: 2 }]);
console.time("op"); /* ... */ console.timeEnd("op");

Output goes to the DevTools Console. Standard browser API; nothing Tauri-specific.

For a console.log that also fires from production, route through Rust:

import { invoke } from "@tauri-apps/api/core";

async function logToBackend(msg: string) {
  await invoke("log", { message: msg });
}
#[tauri::command]
fn log(message: String) {
  println!("[FRONTEND] {}", message);
}

Now production users' issues can be traced via the Rust log if you've set up file-based logging.

Logging from Rust

Simplest: println! and eprintln!. Both write to the terminal where you ran npm run tauri dev.

#[tauri::command]
fn save(text: String) -> Result<(), String> {
  println!("save called with text length: {}", text.len());
  // ...
  Ok(())
}

Run npm run tauri dev. Hit the button that triggers save. The terminal shows the println output.

For long-running apps, use the log crate plus an env logger:

log = "0.4"
env_logger = "0.11"
use log::{info, warn, error, debug};

env_logger::init();
info!("app starting");
debug!("db pool: {:?}", pool);
warn!("non-fatal issue");
error!("boom: {}", err);

Set RUST_LOG=debug (or info, warn, error) to control verbosity:

RUST_LOG=debug npm run tauri dev

env_logger formats logs with timestamps, levels, and module paths. Much nicer than raw println! for serious apps.

tracing for structured logging

For production-grade logging, the tracing crate is the standard:

tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
use tracing::{info, warn, error, instrument};

tracing_subscriber::fmt()
  .with_env_filter("info,my_app=debug")
  .init();

#[instrument]
async fn fetch_user(id: u64) -> Result<User, Error> {
  info!("fetching user");
  // ...
}

#[instrument] automatically logs entry/exit and arguments. with_env_filter lets you control verbosity per module. The output is structured (key=value pairs) and parseable for log-aggregation tools.

File-based logging

For production users who hit bugs, you want logs they can send you. Use the tauri-plugin-log plugin:

cargo add tauri-plugin-log
npm install @tauri-apps/plugin-log
.plugin(tauri_plugin_log::Builder::new()
  .target(tauri_plugin_log::Target::new(
    tauri_plugin_log::TargetKind::LogDir { file_name: None }
  ))
  .build())

Logs go to a file in the app's log directory. From the frontend:

import { info, error } from "@tauri-apps/plugin-log";

info("user clicked save");
error(`save failed: ${err}`);

The plugin captures both Rust and JS logs into a unified file. Add a "Show logs" button to your UI that opens the file in the OS's default viewer.

Tauri-specific debug helpers

println! in Tauri commands works the same as anywhere — output to stdout. For eprintln!, output to stderr. Both visible in tauri dev's terminal.

For panics, the runtime catches them and shows the error in the terminal. A panic will crash the app, so design for graceful errors instead of relying on panics.

Source maps

In tauri dev, Vite produces source maps. When a JS error fires, the DevTools "Sources" tab shows your TypeScript with original line numbers. Set breakpoints there.

In production builds, source maps are usually omitted. To enable for debugging a release build:

// vite.config.ts
export default defineConfig({
  build: { sourcemap: true },
});

Performance debugging

DevTools has a Performance tab for the frontend — record a session, see what's slow.

For Rust performance, use cargo flamegraph:

cargo install flamegraph
cargo flamegraph --bin my-app

Generates an SVG showing where CPU time is spent. Open in a browser to drill into hot functions.

Network debugging

DevTools' Network tab shows every HTTP request if it goes through the browser fetch API. Requests made via tauri-plugin-http's fetch may or may not appear depending on how they're routed.

For Rust-side requests via reqwest, log them yourself:

let resp = reqwest::get(&url).await?;
info!(status = resp.status().as_u16(), url = %url, "http response");

Or wire reqwest to a tracing-aware HTTP client wrapper.

Common mistakes

Looking in the wrong console. println! from Rust is in the terminal. console.log is in DevTools. Confusion about which is which wastes hours.

No logging in production. When the user reports a bug, you have nothing to look at. Set up file-based logging from day one.

Logging too much. Verbose logs in a hot loop fill up the disk and slow the app. Use levels (debug, info, warn, error) and filter by env var.

Logging sensitive data. API keys, passwords, PII shouldn't appear in logs that users might send back.

Debug builds in production. Tauri's release build is npm run tauri build. Don't ship tauri dev's output to users — it's unoptimized and noisy.

What's next

Next lesson: shell commands. Run external processes (git, ffmpeg, your own CLI tools) from a Tauri app and capture their output.

Recap

DevTools for the frontend, terminal/log file for Rust. println! for quick debugging; log + env_logger for medium-grade; tracing for structured production logging. tauri-plugin-log to write logs to a file users can send. Source maps for breaking on TypeScript code. Recordings for performance.

Next: shell commands.

Ready? Take the quiz on the full lesson page →
Test what you've learned. Watch the lesson and try the interactive quiz on the same page.