> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/tighten/ziggy/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Get up and running with Ziggy in minutes. Build your first route()-powered feature from scratch.

# Quickstart Guide

This guide will walk you through creating your first Ziggy-powered feature from a fresh Laravel installation to making your first `route()` call in JavaScript.

## Prerequisites

Before starting, ensure you have:

* Laravel 9.0 or higher installed
* PHP 8.1 or higher
* Node.js and npm (for frontend assets)

## Step 1: Install Ziggy

Install Ziggy via Composer:

```bash theme={null}
composer require tightenco/ziggy
```

<Check>
  Ziggy is now installed and automatically registered!
</Check>

## Step 2: Create Laravel Routes

Let's create a simple blog post feature. Add these routes to `routes/web.php`:

```php routes/web.php theme={null}
use App\Http\Controllers\PostController;

Route::get('/', function () {
    return view('welcome');
})->name('home');

Route::get('/posts', [PostController::class, 'index'])->name('posts.index');
Route::get('/posts/{post}', [PostController::class, 'show'])->name('posts.show');
Route::post('/posts', [PostController::class, 'store'])->name('posts.store');
```

<Note>
  The `.name()` method is crucial—Ziggy only works with **named routes**.
</Note>

## Step 3: Add @routes to Your Layout

Open your main layout file (typically `resources/views/layouts/app.blade.php` or create it if it doesn't exist):

```blade resources/views/layouts/app.blade.php theme={null}
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>{{ config('app.name', 'Laravel') }}</title>
    
    {{-- Add Ziggy routes BEFORE your JavaScript --}}
    @routes
    
    @vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body>
    @yield('content')
</body>
</html>
```

<Warning>
  Place `@routes` **before** `@vite` or any other JavaScript to ensure routes are available when your scripts load.
</Warning>

## Step 4: Create a View with JavaScript

Create a posts listing page at `resources/views/posts/index.blade.php`:

```blade resources/views/posts/index.blade.php theme={null}
@extends('layouts.app')

@section('content')
<div class="container">
    <h1>Blog Posts</h1>
    
    <div id="posts-container">
        <p>Loading posts...</p>
    </div>
    
    <button id="create-post-btn" class="btn btn-primary">
        Create New Post
    </button>
</div>

<script>
    // Fetch posts using Ziggy's route() helper
    fetch(route('posts.index'))
        .then(response => response.json())
        .then(posts => {
            const container = document.getElementById('posts-container');
            
            if (posts.length === 0) {
                container.innerHTML = '<p>No posts yet.</p>';
                return;
            }
            
            container.innerHTML = posts.map(post => `
                <div class="post">
                    <h2>${post.title}</h2>
                    <p>${post.excerpt}</p>
                    <a href="${route('posts.show', post.id)}" class="btn btn-link">
                        Read More
                    </a>
                </div>
            `).join('');
        })
        .catch(error => console.error('Error loading posts:', error));
    
    // Handle create post button
    document.getElementById('create-post-btn').addEventListener('click', () => {
        // Navigate to create page using Ziggy
        window.location.href = route('posts.create');
    });
</script>
@endsection
```

## Step 5: Use route() in Your JavaScript

Let's create a more complex example with Axios in `resources/js/app.js`:

```js resources/js/app.js theme={null}
import axios from 'axios';

// Configure Axios defaults
axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

// Example 1: GET request
function loadPost(postId) {
    return axios.get(route('posts.show', postId))
        .then(response => response.data)
        .catch(error => {
            console.error('Failed to load post:', error);
            throw error;
        });
}

// Example 2: POST request with CSRF token
function createPost(postData) {
    return axios.post(route('posts.store'), postData)
        .then(response => {
            console.log('Post created successfully!');
            // Redirect to the new post
            window.location.href = route('posts.show', response.data.id);
        })
        .catch(error => {
            console.error('Failed to create post:', error);
            throw error;
        });
}

// Example 3: Using with query parameters
function searchPosts(searchTerm, page = 1) {
    const url = route('posts.index', {
        search: searchTerm,
        page: page,
        sort: 'created_at',
    });
    
    return axios.get(url).then(response => response.data);
}

// Make functions available globally
window.loadPost = loadPost;
window.createPost = createPost;
window.searchPosts = searchPosts;
```

## Step 6: Test It Out

<Steps>
  <Step title="Start Your Development Server">
    ```bash theme={null}
    php artisan serve
    ```
  </Step>

  <Step title="Open Browser Console">
    Visit `http://localhost:8000` and open your browser's developer console (F12).
  </Step>

  <Step title="Try Ziggy Commands">
    Test these commands in the console:

    ```js theme={null}
    // Generate a URL
    route('posts.show', 1);
    // Output: 'http://localhost:8000/posts/1'

    // Check if route exists
    route().has('posts.index');
    // Output: true

    // Get current route
    route().current();
    // Output: 'home' (or whatever page you're on)

    // List all routes
    Object.keys(Ziggy.routes);
    // Output: ['home', 'posts.index', 'posts.show', 'posts.store']
    ```
  </Step>
</Steps>

<Check>
  Success! You're now using Ziggy to generate type-safe URLs in JavaScript.
</Check>

## Common Use Cases

### With Alpine.js

```html theme={null}
<div x-data="{
    posts: [],
    async loadPosts() {
        const response = await fetch(route('posts.index'));
        this.posts = await response.json();
    }
}" x-init="loadPosts()">
    <template x-for="post in posts" :key="post.id">
        <a :href="route('posts.show', post.id)" x-text="post.title"></a>
    </template>
</div>
```

### With Vue 3

First, install the Vue plugin:

```js resources/js/app.js theme={null}
import { createApp } from 'vue';
import { ZiggyVue } from 'ziggy-js';

const app = createApp({});

// Install Ziggy's Vue plugin
app.use(ZiggyVue);

app.mount('#app');
```

Then use it in your components:

```vue PostsList.vue theme={null}
<template>
    <div>
        <h1>Posts</h1>
        <div v-for="post in posts" :key="post.id">
            <a :href="route('posts.show', post.id)">
                {{ post.title }}
            </a>
        </div>
    </div>
</template>

<script setup>
import { ref, onMounted, inject } from 'vue';
import axios from 'axios';

const route = inject('route');
const posts = ref([]);

onMounted(async () => {
    const response = await axios.get(route('posts.index'));
    posts.value = response.data;
});
</script>
```

### With React

```jsx PostsList.jsx theme={null}
import React, { useState, useEffect } from 'react';
import { useRoute } from 'ziggy-js';
import axios from 'axios';

export default function PostsList() {
    const route = useRoute();
    const [posts, setPosts] = useState([]);
    
    useEffect(() => {
        axios.get(route('posts.index'))
            .then(response => setPosts(response.data))
            .catch(error => console.error(error));
    }, []);
    
    return (
        <div>
            <h1>Posts</h1>
            {posts.map(post => (
                <div key={post.id}>
                    <a href={route('posts.show', post.id)}>
                        {post.title}
                    </a>
                </div>
            ))}
        </div>
    );
}
```

### With Form Submissions

```html theme={null}
<form id="post-form">
    <input type="text" name="title" placeholder="Post title" required>
    <textarea name="body" placeholder="Post content" required></textarea>
    <button type="submit">Create Post</button>
</form>

<script>
document.getElementById('post-form').addEventListener('submit', async (e) => {
    e.preventDefault();
    
    const formData = new FormData(e.target);
    const data = Object.fromEntries(formData);
    
    try {
        const response = await fetch(route('posts.store'), {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
            },
            body: JSON.stringify(data),
        });
        
        const post = await response.json();
        
        // Redirect to the new post
        window.location.href = route('posts.show', post.id);
    } catch (error) {
        console.error('Error creating post:', error);
        alert('Failed to create post');
    }
});
</script>
```

## Debugging Tips

<AccordionGroup>
  <Accordion title="route() is not defined">
    **Problem:** `Uncaught ReferenceError: route is not defined`

    **Solution:**

    * Ensure `@routes` is added to your layout **before** your JavaScript
    * Clear your view cache: `php artisan view:clear`
    * Check that you're on a page that uses the layout with `@routes`
  </Accordion>

  <Accordion title="Route 'xyz' is not in the route list">
    **Problem:** `Ziggy error: route 'posts.show' is not in the route list`

    **Solution:**

    * Verify the route exists: `php artisan route:list --name=posts.show`
    * Make sure the route has a name: `->name('posts.show')`
    * Clear route cache: `php artisan route:clear`
    * Reload the page to get the latest route list
  </Accordion>

  <Accordion title="Generated URL is wrong">
    **Problem:** URLs have wrong domain or protocol (http vs https)

    **Solution:**

    * Check your `APP_URL` in `.env`
    * Configure trusted proxies if behind a load balancer
    * See the [TLS/SSL termination docs](https://laravel.com/docs/requests#configuring-trusted-proxies)
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Route Parameters" icon="sliders" href="/route-parameters">
    Learn advanced parameter handling and route model binding
  </Card>

  <Card title="Filtering Routes" icon="filter" href="/filtering-routes">
    Control which routes are exposed to JavaScript
  </Card>

  <Card title="TypeScript Setup" icon="code" href="/typescript">
    Enable route name autocompletion with TypeScript
  </Card>

  <Card title="Framework Integration" icon="puzzle-piece" href="/javascript-frameworks">
    Deep dives for Vue, React, and other frameworks
  </Card>
</CardGroup>

## You're All Set!

Congratulations! You've successfully:

<Steps>
  <Step title="Installed Ziggy">✓</Step>
  <Step title="Added the @routes directive">✓</Step>
  <Step title="Created named routes">✓</Step>
  <Step title="Used route() in JavaScript">✓</Step>
</Steps>

You're now ready to build amazing features with type-safe routing!
