Skip to main content
Ziggy 1.0 includes significant improvements and changes, most of which won’t require any changes to existing code!

Quick Summary

If all you’re doing is dropping the @routes Blade directive into a view somewhere and using the JavaScript route() helper function later, you only really need to worry about one thing:
route() with any arguments returns a string now, so:
  • Anywhere you’re calling .url() to get a literal string, remove it
  • Anywhere you’re passing route parameters using .with(), pass them as the second argument to route() instead
  • Anywhere you’re passing query parameters using .withQuery(), pass them along with your route parameters in the second argument to route(). (If any of their names collide with your route parameters, nest your query parameters under a _query key.)

New Features

Route Model Binding Support

Ziggy now fully supports Laravel’s route-model binding functionality. Previously, Ziggy could accept an object as a parameter and use its id key as the actual parameter value in the URL. This feature has been enhanced to: Example:
class Post extends Model
{
    public function getRouteKeyName()
    {
        return 'slug';
    }
}
Route::post('posts/{post}', function (Post $post) {
    return view('posts.show', ['post' => $post]);
})->name('posts.update');
In Ziggy v1, you can pass an object with a slug key into the route() helper:
const post = { 
  id: 15, 
  slug: 'announcing-ziggy-v1', 
  author: 'Jacob', 
  published: false 
};

route('posts.update', post); 
// 'https://ziggy.test/posts/announcing-ziggy-v1'

Parameter Checking with current()

Ziggy’s current() method can now be passed an object of parameters as the second argument, and will return whether those parameter values match in the current URL. Example:
// Route: 'events.venues.show' with URI '/events/{event}/venues/{venue}'
// Current URL: https://myapp.com/events/1/venues/2?authors=all

// Check route name (unchanged)
route().current(); // 'events.venues.show'
route().current('events.venues.show'); // true

// New: Check with parameters
route().current('events.venues.show', { event: 1, venue: 2 }); // true
route().current('events.venues.show', { authors: 'all' }); // true
route().current('events.venues.show', { venue: 6 }); // false

High Impact Changes

route() Now Returns a String

⚠️ Breaking Change: The route() function now returns a literal string if it is passed any arguments.
If you are chaining methods onto a route(...) call with arguments, such as route('posts.show').url() or route('home').withQuery(...), remove the chained methods. Calls specifically to route() with no arguments are not affected and will still return an instance of the Router class, so things like route().current() and route().params still work as expected. Before:
const url = route('posts.show', { post: 1 }).url();
After:
const url = route('posts.show', { post: 1 });

url() Method Removed

⚠️ Breaking Change: The url() method on the Router class was removed.
Because route(...) now returns a string directly, the url() method is no longer necessary. You can safely remove it by finding and replacing instances of '.url()' with '' (nothing). Before:
route('posts.show', { post: 1 }).url();
After:
route('posts.show', { post: 1 });

Medium Impact Changes

Default ziggy:generate Path Changed

⚠️ Breaking Change: The default ziggy:generate path has changed to resources/js/ziggy.js.
The default output path changed from resources/assets/js/ziggy.js to resources/js/ziggy.js to align with Laravel 5.7+ directory structure.

whitelist and blacklist Renamed

⚠️ Breaking Change: The whitelist and blacklist features were renamed to only and except.
All whitelist and blacklist functionality, including config keys and methods, was renamed: Before:
// config/ziggy.php
return [
    'whitelist' => ['home', 'posts.*'],
    'blacklist' => ['admin.*'],
];
After:
// config/ziggy.php
return [
    'only' => ['home', 'posts.*'],
    'except' => ['admin.*'],
];

Boolean Query Parameters Encoded as Integers

⚠️ Breaking Change: Boolean query parameters are now encoded as integers.
Ziggy’s route() function will now encode boolean query parameters as integers (0/1) instead of strings ('true'/'false'). Before:
route('posts.index', { published: true });
// '/posts?published=true'
After:
route('posts.index', { published: true });
// '/posts?published=1'

Low Impact Changes

⚠️ The with() and withQuery() methods on the Router class are deprecated.
Instead of with(), pass parameters as the second argument to route().Instead of withQuery(), pass query parameters in the same object with regular parameters. If you have query parameters and named parameters with the same name, use the special _query key.Before:
route('posts.show').with({ post: 1 }).withQuery({ sort: 'latest' });
After:
route('posts.show', { post: 1, sort: 'latest' });

// With conflicting names, use _query:
route('posts.show', { 
  post: 1, 
  _query: { post: 'extra-param' } 
});
⚠️ The Route Facade macros, Route::only() and Route::except() (previously Route::whitelist() and Route::blacklist()) were removed.
Instead of using these macros in your route files, set the routes to include/exclude in config/ziggy.php.Before:
// routes/web.php
Route::whitelist('home', 'posts.*');
After:
// config/ziggy.php
return [
    'only' => ['home', 'posts.*'],
];
⚠️ The PHP RoutePayload class was renamed to Ziggy.
The ->compile() method was removed in favor of constructing a new instance and calling ->toArray() or ->toJson().Changes:
  • The application router instance is now resolved internally (no longer passed to constructor)
  • new Ziggy(...) now takes only 2 arguments: $group and $url
  • The default value of $basePort changed from false to null
Before:
$payload = new RoutePayload($router, $group, $url);
$compiled = $payload->compile();
After:
$ziggy = new Ziggy($group, $url);
$array = $ziggy->toArray();
$json = $ziggy->toJson();
⚠️ The getRoutePayload() method on the PHP BladeRouteGenerator and CommandRouteGenerator classes was removed.
⚠️ The JavaScript UrlBuilder class was removed.
Refer to the template() getter on the new Route class if you need to re-implement this functionality.
⚠️ The baseProtocol and baseDomain properties were removed from Ziggy’s global configuration object.
Both these values were inferred from the baseUrl property, which is set to your app URL. Refer to the template() getter on the new Route class if you need to re-implement this functionality.
⚠️ base and other prefixes were removed from config keys.
The following configuration properties were renamed:
  • namedRoutesroutes
  • defaultParametersdefaults
  • baseUrlurl
  • basePortport
Before:
return [
    'namedRoutes' => [...],
    'baseUrl' => config('app.url'),
    'basePort' => null,
];
After:
return [
    'routes' => [...],
    'url' => config('app.url'),
    'port' => null,
];
⚠️ The filter() method on the Ziggy class is now ‘fluent’.
The filter() method now returns an instance of Ziggy instead of a collection of routes.Before:
$routes = $ziggy->filter($group, $url);
// Returns collection
After:
$ziggy = $ziggy->filter($group, $url);
// Returns Ziggy instance (fluent)
The following unused methods on the Ziggy class were removed:
  • appendRouteToList()
  • isListedAs()
  • except()
  • only() (redundant/unnecessary)
The following internal methods are now private:On Ziggy class:
  • nameKeyedRoutes()
  • resolveBindings()
  • applyFilters()
  • group()
On CommandRouteGenerator class:
  • generate()
Several undocumented methods and properties on the Router class were removed.Removed properties:
  • name - use the name you were passing into route() as the first argument
  • absolute - use the value you were passing into route() as the third argument
  • ziggy - use the global Ziggy configuration object
  • urlBuilder - refer to the template() getter on the new Route class
  • template - refer to the template() getter on the new Route class
  • urlParams - use the value you were passing into route() as the second argument
  • queryParams - use the value you were passing into withQuery()
  • hydrated - use the returned URL string
Removed methods:
  • normalizeParams() - refer to the internal _parse() method
  • hydrateUrl() - use the returned URL string
  • matchUrl() - use current() or refer to the current() method on the new Route class
  • constructQuery() - use the returned URL string
  • extractParams() - refer to the _dehydrate() method on the Router class
  • parse() - use the returned URL string
  • trimParam() - use .replace(/{|\??}/g, '')
Ziggy’s main build asset/entrypoint is now called index.js instead of route.js.Ziggy’s main JavaScript source and dist files are now called index.js instead of route.js.
The route().check() method is deprecated and will be removed in a future major version of Ziggy.
Use route().has() instead:
// Before (deprecated)
if (route().check('home')) { /* ... */ }

// After
if (route().has('home')) { /* ... */ }

Migration Steps

1

Update Composer dependencies

composer update tightenco/ziggy
2

Remove .url() calls

Find and replace .url() with nothing:
// Before
route('home').url();

// After
route('home');
3

Replace with() and withQuery()

Replace chained methods with second parameter:
// Before
route('posts.show').with({ post: 1 }).withQuery({ sort: 'latest' });

// After
route('posts.show', { post: 1, sort: 'latest' });
4

Update config/ziggy.php

Rename config keys:
  • whitelistonly
  • blacklistexcept
  • namedRoutesroutes
  • defaultParametersdefaults
  • baseUrlurl
  • basePortport
5

Update ziggy:generate path (if customized)

If you specified a custom path for ziggy:generate, update it from resources/assets/js/ziggy.js to resources/js/ziggy.js.
6

Test your application

Thoroughly test all routes and navigation in your application.

Getting Help

If you encounter issues during the upgrade process:

Build docs developers (and LLMs) love