팀 내부에서 쓸 데스크톱 툴이 하나 필요해졌다. 로컬 파일시스템 접근이 필요했고, macOS와 Windows 양쪽 다 돌아가야 했다.
처음엔 당연히 Electron을 생각했다. 익숙한 스택이고 자료도 많다. 근데 Electron 앱은 번들 크기가 기본 100MB를 훌쩍 넘는다. Chromium 전체를 같이 패키징하기 때문이다. 사내 툴 하나 때문에 그 무게를 지기엔 좀 과하다 싶었다. 그러다가 Tauri를 다시 들여다봤다.
Tauri가 하는 일
Tauri는 Rust로 만든 데스크톱 앱 프레임워크다. Chromium을 내장하는 대신, 각 OS의 내장 WebView를 쓴다. macOS는 WKWebView, Windows는 WebView2 (Edge에 내장된 Chromium 기반이라 별도 설치 불필요), Linux는 WebKitGTK.
번들 크기가 확 줄어드는 게 핵심이다. Hello World 앱 기준으로 Electron은 200MB 안팎인데, Tauri는 3-5MB 수준이다.
프로젝트 세팅
npm create tauri-app@latest my-app
프레임워크 선택지에서 Next.js, Vite, SvelteKit 등이 나온다. Next.js를 고르면 Tauri v2 기준 설정이 잡힌 상태로 시작된다.
Next.js App Router에 붙이는 경우 정적 익스포트가 필요하다.
// next.config.js
const nextConfig = {
output: 'export',
trailingSlash: true,
images: { unoptimized: true },
};
Tauri는 빌드 시 정적 파일을 번들에 포함하는 구조라 런타임 서버가 없다. Server Components나 Server Actions는 쓸 수 없다는 게 제약이다. API 호출이 필요한 기능은 외부 API를 직접 부르거나, Tauri의 Rust 사이드 커맨드로 처리한다.
Rust 커맨드로 파일 접근하기
OS 레벨 기능은 Rust에서 처리하고, 프론트엔드에서 invoke로 호출하는 패턴을 쓴다.
// src-tauri/src/lib.rs
#[tauri::command]
fn list_directory(path: String) -> Result<Vec<String>, String> {
std::fs::read_dir(&path)
.map_err(|e| e.to_string())?
.filter_map(|e| e.ok())
.map(|e| Ok(e.file_name().to_string_lossy().into_owned()))
.collect()
}
pub fn run() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![list_directory])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
// 프론트엔드
import { invoke } from '@tauri-apps/api/core';
const files = await invoke<string[]>('list_directory', { path: '/Users/me/Documents' });
Rust를 깊이 몰라도 기본적인 파일 I/O 수준은 어떻게든 된다. 다만 Rust 컴파일 에러는 처음 보면 좀 무섭게 생겼다. 타입 체크가 엄격해서 한 번 빌드가 통과되면 런타임 오류가 거의 안 난다는 건 확실히 장점이다.
빌드와 배포
npm run tauri build
macOS에서는 src-tauri/target/release/bundle/ 아래에 .app과 .dmg가 생성된다. 처음 빌드는 Rust 컴파일 때문에 3-5분 걸리는데, 이후엔 캐시 덕분에 빠르다.
코드 사이닝이 없으면 macOS에서 "개발자를 확인할 수 없습니다" 경고가 뜬다. 사내 배포라면 우클릭 → 열기로 우회하거나, 팀 내 MDM을 통해 배포할 수 있다. 외부 사용자한테 배포해야 한다면 Apple Developer 계정($99/년)이 필요하다.
Electron과 비교
| 항목 | Electron | Tauri v2 | |------|----------|----------| | 번들 크기 | 100-200MB+ | 3-10MB | | 메모리 사용 | 높음 | 낮음 | | 백엔드 언어 | JS/TS | Rust | | Server-side 렌더링 | 가능 | 불가 (정적 빌드) | | 학습 곡선 | 낮음 | Rust 진입장벽 있음 | | 커뮤니티 | 크고 성숙 | 빠르게 성장 중 |
사내 툴이라는 용도에는 Tauri가 맞는 선택이었다. 번들 크기와 메모리 모두 체감이 될 정도로 차이가 났다. Rust를 깊이 알 필요는 없지만, #[tauri::command]와 invoke 패턴 정도는 익혀야 실용적으로 쓸 수 있다. 정적 빌드 제약만 감수할 수 있다면, 가벼운 데스크톱 툴 만들기에는 Electron보다 훨씬 나은 선택이다.