C.W.K.
Stream
Lesson 04 of 07 · published

fs, dialog, shell: Touching the System

~14 min · tauri, fs, dialog, shell

Level 0Web Tourist
0 XP0/56 lessons0/13 achievements
0/100 XP to next level100 XP to go0% complete
"These three plugins are where your app reaches into the user's machine — which makes them exactly where you must be most careful."

fs: Reading and Writing Files

The fs plugin gives the frontend file access — readTextFile, writeTextFile, readDir, and friends — but only within the paths your capability scopes allow (the security track's lesson made flesh). The pattern: scope reads/writes to $APPDATA or a folder the user explicitly picked, never the whole disk. fs is the plugin where a sloppy scope turns into a real vulnerability, so it's the one to scope tightest.

dialog: Native Pickers and Prompts

The dialog plugin shows real OS dialogs: open (file/folder picker), save (save-as), and message-style message/ask/confirm. There's a lovely synergy with fs: let the user pick a file with the dialog, and the returned path is one the user consciously chose — a natural, safe way to grant access beyond your default scope without opening the whole filesystem.

shell: Opening and Executing — Carefully

The shell plugin (and the focused opener plugin) can open a URL or file in the user's default app, and can execute processes. Opening a URL is low-risk; executing arbitrary commands is the single most dangerous power in the toolkit. If you grant shell execution, scope it to specific, fixed commands — never let the frontend pass an arbitrary command string. For just opening links, prefer opener over full shell execution; it's the smaller, safer grant.

Code

Pick-then-read, and open a URL safely·tsx
import { open } from "@tauri-apps/plugin-dialog";
import { readTextFile } from "@tauri-apps/plugin-fs";
import { openUrl } from "@tauri-apps/plugin-opener";

// dialog → fs synergy: the user picks the file, so the path is trusted.
const path = await open({ multiple: false, filters: [{ name: "Text", extensions: ["txt", "md"] }] });
if (typeof path === "string") {
  const contents = await readTextFile(path);
  console.log(contents);
}

// Opening a link in the default browser — low-risk, prefer opener.
await openUrl("https://v2.tauri.app/");

External links

Exercise

Build a 'open and show a file' flow: use the dialog plugin to let the user pick a .txt file, then the fs plugin to read and display it. Note that you didn't need broad filesystem scope — the dialog handed you a user-chosen path. Then write one sentence on why you'd avoid shell execute for this and what you'd use instead if you needed to open the file externally.
Hint
dialog.open() returns the chosen path; readTextFile(path) reads it. You avoid shell execute because it's the highest-risk grant; to open the file in its default app, use the opener plugin (openPath), not a shell command.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.