# How to Configure Desktop-Aware Fetch for Tauri Runtime (127.0.0.1:3210) in Routa

> Configure desktop-aware fetch for Tauri runtime in Routa. Automatically rewrite API calls to 127.0.0.1:3210 in Tauri webview and use standard HTTP endpoints for web.

- Repository: [Fengda Huang/routa](https://github.com/phodal/routa)
- Tags: how-to-guide
- Published: 2026-05-26

---

**Routa's `desktopAwareFetch` helper automatically detects Tauri desktop mode and rewrites API calls to `http://127.0.0.1:3210` when running inside the Tauri webview, while using standard HTTP endpoints for web deployments.**

When building cross-platform applications with [phodal/routa](https://github.com/phodal/routa), your frontend must handle two distinct runtime environments: a traditional web app served over HTTP/HTTPS and a desktop application packaged with Tauri. Since Tauri serves the UI from the `tauri://` scheme without an attached backend server, standard `/api/*` requests fail unless you configure desktop-aware fetch to route traffic to the embedded Rust server.

## Understanding the Desktop-Aware Fetch Architecture

The `desktopAwareFetch` function in [`src/client/utils/diagnostics.ts`](https://github.com/phodal/routa/blob/main/src/client/utils/diagnostics.ts) serves as a transparent proxy that determines the correct API base URL based on the current runtime context.

### Runtime Detection Mechanisms

Routa identifies Tauri environments through `isTauriRuntime()`, which checks for the presence of `window.__TAURI__` or `window.__TAURI_INTERNALS__` globals. Alternatively, you can force desktop mode by appending `?runtime=tauri` to the URL, which persists a marker in `localStorage` via `hasPersistedTauriMarker()`.

For static builds, `isDesktopStaticRuntime()` performs an additional protocol check. It returns `true` only when running inside Tauri **and** the page protocol is not `http:` or `https:` (confirming the `tauri://` scheme). This distinction prevents false positives during regular web development.

### Embedded Server Address Resolution

When `isDesktopStaticRuntime()` returns `true`, `getDesktopApiBaseUrl()` returns the default embedded server address `http://127.0.0.1:3210`. This port is defined by the constant `DESKTOP_API_DEFAULT_PORT` in [`src/client/utils/diagnostics.ts`](https://github.com/phodal/routa/blob/main/src/client/utils/diagnostics.ts). If you supply a custom backend URL through configuration, that value overrides the default localhost endpoint.

## Configuring the Backend URL

Routa supports three methods for overriding the default `127.0.0.1:3210` endpoint, checked in priority order by `getConfiguredBackendBaseUrl()` in [`src/client/config/backend.ts`](https://github.com/phodal/routa/blob/main/src/client/config/backend.ts):

**Query String Parameter**
Append `?backend=https://my-api.example.com` to the application URL. The helper reads this value once, stores it in `localStorage`, and uses it for the remainder of the session.

**Local Storage**
Programmatically set the backend URL for persistent configuration:

```typescript
localStorage.setItem('routa.backendBaseUrl', 'https://api.production.com');

```

**Environment Variable**
For static builds, set `NEXT_PUBLIC_ROUTA_BACKEND_BASE_URL` at build time. The `readFromEnv()` function reads this during initialization.

The resolution logic follows this cascade: **query parameter** → **localStorage** → **environment variable** → **default localhost:3210**.

## Implementing Desktop-Aware Fetch in Your Code

The `desktopAwareFetch` function in [`src/client/utils/diagnostics.ts`](https://github.com/phodal/routa/blob/main/src/client/utils/diagnostics.ts) automatically handles URL resolution and request building:

```typescript
// src/client/utils/diagnostics.ts
export function desktopAwareFetch(
  path: string,
  options?: RequestInit,
): Promise<Response> {
  const base = getDesktopApiBaseUrl();        // "" for web, or http://127.0.0.1:3210
  return fetch(resolveApiPath(path, base), options);
}

```

The `resolveApiPath` helper (from [`src/client/config/backend.ts`](https://github.com/phodal/routa/blob/main/src/client/config/backend.ts)) ensures the final URL always includes the `/api` prefix. When `base` is an empty string (standard web mode), requests target the current origin. In Tauri static mode, requests route to `http://127.0.0.1:3210/api/...` or your configured custom URL.

### Basic Usage Example

```typescript
import { desktopAwareFetch } from '@/client/utils/diagnostics';

export async function loadWorkspaceData(workspaceId: string) {
  // Works identically in browser and Tauri desktop
  const resp = await desktopAwareFetch(`/api/workspaces/${workspaceId}`);
  if (!resp.ok) throw new Error('Failed to load workspace');
  return resp.json();
}

```

### Environment-Based Configuration

Configure a remote API for your desktop build without code changes:

```bash

# .env.local

NEXT_PUBLIC_ROUTA_BACKEND_BASE_URL=https://api.mycompany.com

```

```typescript
// Automatically uses the environment variable
const resp = await desktopAwareFetch('/api/tasks');

```

### Dynamic Backend Override

For one-off testing against staging servers, launch the Tauri app with a query parameter:

```

tauri://localhost?backend=https://staging.api.example.com

```

Subsequent API calls will target the staging environment:

```typescript
await desktopAwareFetch('/api/projects');
// Resolves to: https://staging.api.example.com/api/projects

```

## Rust Server and Error Handling

On the backend, [`crates/routa-server/src/lib.rs`](https://github.com/phodal/routa/blob/main/crates/routa-server/src/lib.rs) starts the embedded HTTP server on port 3210 with appropriate CORS settings to accept requests from the Tauri webview.

If the frontend attempts API calls while in static desktop mode but `getDesktopApiBaseUrl()` returns an empty string (indicating the Rust server failed to start), `desktopStaticApiError()` throws a descriptive error. This safeguard prevents silent failures when the desktop backend is unavailable during development or production.

Enable debug logging by setting `window.__ROUTA_DEBUG__ = true` or adding `routa.debug=1` to `localStorage` to trace runtime detection logic via the `logRuntime` utility.

## Summary

- **`desktopAwareFetch`** in [`src/client/utils/diagnostics.ts`](https://github.com/phodal/routa/blob/main/src/client/utils/diagnostics.ts) transparently routes API calls to `http://127.0.0.1:3210` when running inside Tauri's `tauri://` scheme.
- **Runtime detection** relies on `window.__TAURI__` globals or the `?runtime=tauri` query parameter with `localStorage` persistence.
- **Backend overrides** support three sources: query strings, `localStorage` (`routa.backendBaseUrl`), and the `NEXT_PUBLIC_ROUTA_BACKEND_BASE_URL` environment variable.
- **Path resolution** via `resolveApiPath` in [`src/client/config/backend.ts`](https://github.com/phodal/routa/blob/main/src/client/config/backend.ts) guarantees consistent `/api` prefixing regardless of runtime.
- **Error handling** prevents API calls when the desktop server is unreachable, protecting against misconfiguration in packaged builds.

## Frequently Asked Questions

### How does Routa detect whether it's running inside Tauri?

Routa's `isTauriRuntime()` function checks for `window.__TAURI__` or `window.__TAURI_INTERNALS__` globals. Additionally, if you load the app with `?runtime=tauri`, the system stores a persistent marker in `localStorage` via `hasPersistedTauriMarker()`, ensuring desktop mode persists across reloads even if the Tauri globals are temporarily unavailable.

### Can I use a custom API URL instead of localhost:3210 for the desktop app?

Yes. You can set `NEXT_PUBLIC_ROUTA_BACKEND_BASE_URL` during build time, use `localStorage.setItem('routa.backendBaseUrl', 'https://api.example.com')`, or append `?backend=https://api.example.com` to the URL. The `getConfiguredBackendBaseUrl()` function reads these in that priority order, allowing the desktop app to communicate with remote APIs instead of the embedded Rust server.

### What happens if the Rust server on port 3210 isn't running?

If `isDesktopStaticRuntime()` returns `true` but `getDesktopApiBaseUrl()` returns an empty string (indicating no backend URL is configured or the default server is unreachable), the `desktopStaticApiError()` function throws an error with a helpful message. This prevents the frontend from attempting requests to non-existent endpoints and alerts you that the desktop backend needs to be started.

### Do I need to change my fetch calls when building for web vs. desktop?

No. The `desktopAwareFetch` utility abstracts runtime differences. Use it consistently across your codebase—it automatically uses the current origin for web deployments and switches to `http://127.0.0.1:3210` (or your configured URL) when running inside Tauri. The helper is used throughout the codebase, including in utilities like [`src/client/utils/repo-validation.ts`](https://github.com/phodal/routa/blob/main/src/client/utils/repo-validation.ts).