---
title: Debugging
url: "https://native-sdk.dev/docs/debugging"
docs_index: /llms.txt
lastUpdated: 2026-10-16
---

> For an index of all documentation, see [/llms.txt](/llms.txt).

The Native SDK provides structured tracing, persistent logging, panic capture, and diagnostic tools for debugging desktop apps.

## macOS WebView inspection

For the macOS system WebView backend, Debug app builds enable Safari inspection,
developer extras, and the default **Toggle Web Inspector** menu item. ReleaseFast,
ReleaseSafe, and ReleaseSmall builds disable them, including the separate release
binary produced by `zig build package` in an expanded build. This applies to
primary WebViews, secondary windows, and child WebViews, including ones created
later by a native-rendered app.

Override the default with a build option:

```bash
native dev -Dwebview-inspect=false
native build -Dwebview-inspect=true
```

Apps that own their build can pass the same option to `zig build` or
`zig build package`. Enabling inspection in a release build allows an attached
Safari console to execute JavaScript in the page's origin, including its allowed
native bridge commands. Keep it disabled for normal distribution.

Lower-level hosts initialized directly through `AppInfo` default to inspection
disabled; set `webview_inspection = true` explicitly for debugging. This setting
covers WKWebView on macOS and does not configure Chromium or other platforms.

## Trace modes

The runtime emits structured trace records. Control verbosity with `TraceMode`:

<table>
  <thead>
    <tr>
      <th>
        Mode
      </th>

      <th>
        Description
      </th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>
        `off`
      </td>

      <td>
        No trace output
      </td>
    </tr>

    <tr>
      <td>
        `events`
      </td>

      <td>
        Lifecycle and platform events only (default)
      </td>
    </tr>

    <tr>
      <td>
        `runtime`
      </td>

      <td>
        Runtime internals: frame timing, invalidation, window state
      </td>
    </tr>

    <tr>
      <td>
        `all`
      </td>

      <td>
        Everything
      </td>
    </tr>
  </tbody>
</table>

Enable at build time with `-Dtrace=true`, or parse from a string:

```zig
const mode = native_sdk.debug.parseTraceMode("all"); // returns ?TraceMode
```

## Trace sinks

Trace records are routed through sinks. Native SDK provides three:

**FileTraceSink** -- appends records to a file on disk:

```zig
var file_sink = native_sdk.debug.FileTraceSink.init(io, log_dir, log_file, .json_lines);
```

**FanoutTraceSink** -- broadcasts to multiple child sinks (e.g. stdout + file):

```zig
var sinks = [_]trace.Sink{ stdout_sink.sink(), file_sink.sink() };
var fanout = native_sdk.debug.FanoutTraceSink{ .sinks = &sinks };
```

**StdoutTraceSink** (from Native SDK's trace module) -- writes to stdout for interactive development.

Wire a sink into the runtime via `RuntimeOptions.trace_sink`:

```zig
var runtime = native_sdk.Runtime.init(.{
    .platform = my_platform,
    .trace_sink = fanout.sink(),
});
```

## Log format

The `NATIVE_SDK_LOG_FORMAT` environment variable controls the persistent log format:

<table>
  <thead>
    <tr>
      <th>
        Value
      </th>

      <th>
        Description
      </th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>
        `jsonl`
      </td>

      <td>
        JSON Lines -- one JSON object per trace record (default)
      </td>
    </tr>

    <tr>
      <td>
        `text`
      </td>

      <td>
        Human-readable text lines
      </td>
    </tr>
  </tbody>
</table>

## Log paths

Default log file locations by platform:

<table>
  <thead>
    <tr>
      <th>
        Platform
      </th>

      <th>
        Path
      </th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>
        macOS
      </td>

      <td>
        `~/Library/Logs/<bundle-id>/native-sdk.jsonl`
      </td>
    </tr>

    <tr>
      <td>
        Linux
      </td>

      <td>
        `~/.local/state/<bundle-id>/logs/native-sdk.jsonl`
      </td>
    </tr>

    <tr>
      <td>
        Windows
      </td>

      <td>
        `%LOCALAPPDATA%&lt;bundle-id>\Logs\native-sdk.jsonl`
      </td>
    </tr>
  </tbody>
</table>

Override with `NATIVE_SDK_LOG_DIR`:

```bash
NATIVE_SDK_LOG_DIR=/tmp/my-logs native dev
```

## Panic capture

The Native SDK captures Zig panics before the default handler runs:

1. Writes a report to `last-panic.txt` in the log directory (includes panic message and return address)
2. Appends a `fatal` trace record to the log file
3. Invokes `std.debug.defaultPanic` for the normal Zig panic output

Enable in your app:

```zig
pub const panic = std.debug.FullPanic(native_sdk.debug.capturePanic);
```

Then call `installPanicCapture` during startup:

```zig
native_sdk.debug.installPanicCapture(io, log_setup.paths);
```

## Debug overlay

For apps with [web content](/docs/frontend), build with `-Ddebug-overlay=true` to enable a visual debugging overlay in the WebView. This shows frame timing, invalidation regions, and window metadata.

```bash
native dev -Ddebug-overlay=true
```

See also [native doctor](/docs/debugging/doctor) for a full diagnostic tool reference.

## Environment variables

<table>
  <thead>
    <tr>
      <th>
        Variable
      </th>

      <th>
        Description
      </th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>
        `NATIVE_SDK_LOG_DIR`
      </td>

      <td>
        Override log output directory
      </td>
    </tr>

    <tr>
      <td>
        `NATIVE_SDK_LOG_FORMAT`
      </td>

      <td>
        Log format:

        `text`

        or

        `jsonl`

        (default:

        `jsonl`

        )
      </td>
    </tr>
  </tbody>
</table>

---

For a semantic overview of all documentation, see [/sitemap.md](/sitemap.md)

For an index of all available documentation, see [/llms.txt](/llms.txt)

For agent-facing discovery, including API and MCP surfaces, see [/agents.md](/agents.md)