Routing & Navigation

How litestar-vite routing compares to Laravel/Ziggy and works with Inertia’s standard APIs.

See also

Official Inertia.js docs: Links | Manual Visits

Key Differences from Laravel/Ziggy

If you’re coming from Laravel with Ziggy, here’s what’s different:

Feature

Laravel/Ziggy

litestar-vite

Route helper

Global route() function

Imported route() from generated file

Inertia router

Monkey-patched with Ziggy

Unmodified, standard Inertia

Plain URLs

Work but bypass types

First-class support

Type safety

Optional (TypeScript)

Full inference from Python

The key principle: litestar-vite provides type-safe route helpers as optional utilities, not as a requirement. Inertia’s standard router APIs work perfectly with plain URL strings.

Plain URLs Work Everywhere

You are not required to use the route() helper. Plain URL strings work with all Inertia APIs:

import { Link } from "@inertiajs/react";

// Both are valid:
<Link href="/users">Users</Link>
<Link href={route("users")}>Users</Link>
import { router } from "@inertiajs/react";

// Both are valid:
router.visit("/users/123");
router.visit(route("user-profile", { userId: 123 }));
import { router } from "@inertiajs/react";

// All standard Inertia methods work with plain URLs:
router.get("/users");
router.post("/users", { data: { name: "John" } });
router.put("/users/123", { data: { name: "Jane" } });
router.delete("/users/123");

Using the Route Helper

The route() helper provides optional type safety for route names and parameters:

import { route } from "@/generated/routes";

// Type-safe route names (autocomplete + compile-time checking)
const url = route("user-profile", { userId: 123 });

// TypeScript errors on invalid routes
const url = route("invalid-route");  // Error: Route not found

// TypeScript errors on missing parameters
const url = route("user-profile");  // Error: Missing userId

Comparison Examples

Here’s the same navigation written two ways:

1. Plain URLs (Always Works)

import { Link } from "@inertiajs/react";
import { router } from "@inertiajs/react";

// Link
<Link href="/users/123">View User</Link>

// Programmatic navigation
router.visit("/users/123");
router.post("/users", { data: { name: "John" } });

2. With route() Helper (Type-Safe)

import { Link } from "@inertiajs/react";
import { router } from "@inertiajs/react";
import { route } from "@/generated/routes";

// Link - route() returns a string URL
<Link href={route("user-profile", { userId: 123 })}>View User</Link>

// Programmatic navigation - standard Inertia router with type-safe URLs
router.visit(route("user-profile", { userId: 123 }));
router.post(route("users"), { data: { name: "John" } });

The route() helper just returns a plain string, so it works directly with Inertia’s standard router - no special wrappers needed.

Global Route (Ziggy-Style)

For a more Laravel/Ziggy-like experience, you can enable global registration of route():

from litestar_vite.config import TypeGenConfig

ViteConfig(
    types=TypeGenConfig(
        global_route=True,  # Register route() on window
    ),
)

When enabled, the generated routes.ts includes:

// Automatically added at end of routes.ts
if (typeof window !== "undefined") {
  window.route = route
}

Now you can use route() without imports:

// No import needed!
<Link href={window.route("user-profile", { userId: 123 })}>View User</Link>

// Or in vanilla JS
router.visit(window.route("users"));

Tip

For full TypeScript support with the global, add to your global.d.ts:

declare const route: typeof import("@/generated/routes").route

This gives you autocomplete even without importing.

Note

The default is global_route=False because explicit imports are better for:

  • Tree-shaking: Unused routes can be eliminated

  • Explicitness: Clear where route() comes from

  • Testing: Easier to mock in unit tests

Interoperability

The route() helper returns a plain string, so it works seamlessly with:

  • Inertia’s <Link> component

  • Inertia’s router.visit(), router.get(), router.post(), etc.

  • Standard fetch() calls

  • Any function expecting a URL string

import { route } from "@/generated/routes";

const url = route("user-profile", { userId: 123 });
console.log(typeof url);  // "string"
console.log(url);         // "/users/123"

// Works with anything expecting a string
fetch(url);
window.location.href = url;
router.visit(url);

Migration from Laravel/Ziggy

If you’re migrating from Laravel with Ziggy:

  1. Replace the global: Change route("name") to import { route } from "@/generated/routes"

  2. Update imports: The route helper is imported, not global

  3. Keep your URLs: Plain URLs continue to work - you can migrate incrementally

// Before (Laravel/Ziggy - global)
router.visit(route("users.show", { user: 123 }));

// After (litestar-vite - imported)
import { route } from "@/generated/routes";
router.visit(route("user-profile", { userId: 123 }));

// Or just use plain URLs (also valid!)
router.visit("/users/123");

Route Naming Conventions

litestar-vite uses kebab-case for route names by default (converted from Python function names):

@get("/users/{user_id}", component="UserProfile")
async def user_profile(user_id: int) -> dict:
    ...  # Route name: "user-profile"

@get("/users", component="Users")
async def list_users() -> dict:
    ...  # Route name: "list-users"

This differs from Laravel’s dot notation (users.show), but you can customize route names:

@get("/users/{user_id}", component="UserProfile", name="users.show")
async def user_profile(user_id: int) -> dict:
    ...  # Route name: "users.show" (custom)

See Also