Skip to Content

tynd.config.ts

Project config. Validated by valibot  — invalid shape fails fast with a clear error message listing every bad field.

tynd.config.ts
import type { TyndConfig } from "@tynd/cli"; export default { runtime: "lite", backend: "backend/main.ts", frontendDir: "dist", icon: "public/favicon.svg", } satisfies TyndConfig;

Window / menu / tray config lives in the backend, not in tynd.config.ts. Each spawned window can configure itself programmatically, so app.start({ window: {...}, menu: [...], tray: {...} }) is the authoritative place. See Backend API.

Top-level fields

FieldDefaultDescription
runtime"full""full" (Bun subprocess) or "lite" (embedded QuickJS)
backend"backend/main.ts"Backend entry file
frontendDir"frontend"Built frontend output directory
frontendEntrySingle TS/JS entry without a framework — auto-bundled
devUrlautoDev server URL override
devCommandautoDev server start command override
iconautoApp icon path (SVG / PNG / ICO)
binaryArgsExtra args passed to the tynd-full / tynd-lite binary
protocolsCustom URL schemes to register (e.g. ["myapp"])
sidecarsBundled binaries
bundleInstaller metadata + signing

sidecars

Binaries bundled inside your app.

sidecars: [ { name: "ffmpeg.exe", path: "bin/ffmpeg.exe" }, { name: "yt-dlp", path: "bin/yt-dlp" }, ]
  • name — resolved at runtime via sidecar.path(name).
  • path — relative to the project root at build time.

See the Sidecars guide.

protocols

Custom URL schemes registered by the installer.

protocols: ["myapp", "myapp-dev"]

Must match /^[a-zA-Z][a-zA-Z0-9+\-.]*$/. Reserved schemes are rejected at config-validation time:

http, https, file, ftp, mailto, javascript, data, about, blob, tynd, tynd-bin

See the Deep Linking guide.

bundle

Required only when using tynd build --bundle.

bundle: { identifier: string, // reverse-DNS (e.g. com.example.myapp), required displayName?: string, // shown in installers / menus categories?: string[], // XDG / Launch Services shortDescription?: string, longDescription?: string, copyright?: string, deb?: { depends?: string[], section?: string, // e.g. "utils" priority?: string, // e.g. "optional" }, rpm?: { license?: string, // SPDX id, e.g. "MIT" requires?: string[], }, appimage?: { /* reserved — currently empty */ }, nsis?: { installMode?: "currentUser" | "perMachine" | "both", // default "currentUser" }, msi?: { upgradeCode?: string, // GUID — pin to enable in-place upgrades }, sign?: { /* see below */ }, }

bundle.sign.windows

windows: { certificate: string, // path to .pfx / .p12, OR "cert:subject=..." for Windows cert store password?: string, // plain or "env:NAME" (recommended) timestampUrl?: string, // default: http://timestamp.digicert.com }

bundle.sign.macos

macos: { identity: string, // "Developer ID Application: Name (TEAMID)" or a SHA-1 hash entitlements?: string, // path to an entitlements.plist notarize?: { appleId: string, // plain or "env:APPLE_ID" password: string, // app-specific password, plain or "env:NAME" teamId: string, }, }

See the Code Signing guide.

env:NAME references

Any string field in bundle.sign.* can use env:NAME to read from process.env.NAME at build time. Missing env vars throw — no silent fallback to unsigned builds.

sign: { windows: { certificate: "./cert.pfx", password: "env:WIN_CERT_PASSWORD", }, macos: { notarize: { appleId: "env:APPLE_ID", password: "env:APPLE_APP_PASSWORD", teamId: "env:APPLE_TEAM_ID", }, }, }

Icon

Auto-detected if icon is not set:

  1. public/{favicon,icon,logo}.svg
  2. public/{favicon,icon,logo}.{ico,png}
  3. assets/icon.{svg,png,ico}
  4. icon.{svg,png,ico}

Override via icon: "path/to/source.svg".

Single source renders per-format:

  • Windows ICO (16/32/48/256)
  • macOS ICNS (32/128/256/512/1024)
  • Linux hicolor PNG set (16/32/48/64/128/256/512)

PNG source degrades to single-size. ICO source passes through to Windows only.

See the Bundling guide.

Window / menu / tray

These live in the backend, not the config file:

backend/main.ts
import { app } from "@tynd/core"; app.start({ window: { title: "My App", width: 1200, height: 800, center: true, }, menu: [ /* … */ ], tray: { /* … */ }, });

Rationale: each spawned window can define its own settings programmatically; a static config file can’t express that flexibility. See Backend API.

Validation

Run tynd validate to typecheck the config + confirm the Rust host binary is discoverable.

Last updated on