nikolawd / laravel-route-disabling
Temporarily disable Laravel routes without removing them from the codebase. Originally proposed for Laravel core.
Package info
github.com/NikolaWd/laravel-route-disabling
pkg:composer/nikolawd/laravel-route-disabling
Requires
- php: ^8.2
- illuminate/routing: ^11.0|^12.0
- illuminate/support: ^11.0|^12.0
- laravel/serializable-closure: ^2.0
Requires (Dev)
- orchestra/testbench: ^9.0|^10.0
- phpunit/phpunit: ^11.0
README
Temporarily disable Laravel routes without removing them from the codebase. Perfect for maintenance mode, feature flags, A/B testing, and gradual rollouts.
The implementation follows Laravel's internal patterns for route handling and has been thoroughly tested to work with route caching.
Installation
You can install the package via Composer:
composer require nikolawd/laravel-route-disabling
The package will automatically register its service provider.
Usage
Basic Usage - Default Message
Route::get('/users', [UserController::class, 'index'])->disabled(); // Returns Laravel's default 503 error page with message: "This route is temporarily disabled."
Custom Message
Route::get('/users', [UserController::class, 'index']) ->disabled('User management is under maintenance'); // Returns Laravel's 503 error page with your custom message
The package uses Laravel's native error handling system (abort(503, $message)), which means:
- Laravel automatically displays its styled 503 error page
- You can customize the page by creating
resources/views/errors/503.blade.phpin your app - The
$exception->getMessage()variable contains your custom message - Full compatibility with Laravel's exception handling
Custom Response with Callback
Route::get('/users', [UserController::class, 'index']) ->disabled(function ($request) { return response()->json([ 'message' => 'This feature is temporarily unavailable', 'retry_after' => now()->addHours(2)->timestamp, ], 503); });
Conditional Disabling
Route::get('/beta-feature', [BetaController::class, 'index']) ->disabled(config('features.beta_disabled') ? 'Beta features are disabled' : false);
Dynamic Enabling/Disabling
Return null or false from a callback to allow the route to proceed normally:
Route::get('/premium-feature', [PremiumController::class, 'index']) ->disabled(function ($request) { if ($request->user()?->isPremium()) { return null; // Allow access for premium users } return response()->json([ 'message' => 'This feature requires a premium subscription', ], 403); });
Use Cases
1. Selective Maintenance Mode
Disable specific routes without putting the entire application in maintenance mode:
Route::get('/checkout', [CheckoutController::class, 'index']) ->disabled('Checkout is temporarily unavailable for system maintenance');
2. Feature Flags
Easily toggle features on/off based on configuration or environment:
Route::get('/new-dashboard', [DashboardController::class, 'new']) ->disabled(!config('features.new_dashboard_enabled'));
3. Time-Based Availability
Enable routes only during specific time periods:
Route::get('/christmas-sale', [SaleController::class, 'christmas']) ->disabled(function ($request) { $now = now(); if ($now->between('2025-12-24', '2025-12-26')) { return null; // Enable during Christmas } return 'Christmas sale is only available December 24-26'; });
4. Business Hours
Restrict access to certain routes during business hours:
Route::post('/trading/execute', [TradingController::class, 'execute']) ->disabled(function ($request) { if (now()->isWeekend() || now()->hour < 9 || now()->hour >= 17) { return response()->json([ 'message' => 'Trading is only available 9 AM - 5 PM on weekdays', ], 503); } return null; // Enable during business hours });
5. Gradual Rollouts
Enable features for a percentage of users:
Route::get('/new-feature', [FeatureController::class, 'index']) ->disabled(function ($request) { // Enable for 20% of users based on user ID if (($request->user()->id % 5) === 0) { return null; } return 'New feature coming soon!'; });
6. Emergency Response
Quickly disable problematic endpoints in production:
Route::post('/problematic-endpoint', [ProblematicController::class, 'store']) ->disabled('This endpoint is temporarily disabled due to a known issue');
Route Caching Support
This package fully supports Laravel's route caching (php artisan route:cache). Closures are automatically serialized and deserialized using Laravel's SerializableClosure, following the same pattern as Laravel's core routing system.
# Works perfectly with route caching
php artisan route:cache
Testing
composer test
Customizing the 503 Error Page
Since the package uses Laravel's native error handling, you can customize the 503 error page just like any other Laravel error page:
- Create
resources/views/errors/503.blade.phpin your application - Use
$exception->getMessage()to display your custom message
Example custom error page:
<!DOCTYPE html> <html> <head> <title>Service Unavailable</title> </head> <body> <h1>503 - Service Unavailable</h1> <p>{{ $exception->getMessage() }}</p> <a href="{{ url('/') }}">Back to Home</a> </body> </html>
Laravel will automatically use your custom view instead of the default error page.
How It Works
The package uses Laravel's macro system to add disabled() and getDisabled() methods to the Route class with full type hinting support. When a route is disabled:
- The disabled status/message/callback is stored in the route action array
- A middleware is automatically registered to the route
- The middleware checks if the route is disabled
- For simple messages, it calls
abort(503, $message)which triggers Laravel's error handling - If a callback is provided, it's executed and the response is returned
- If the callback returns
nullorfalse, the request proceeds normally
For route caching:
- Closures are serialized using
SerializableClosure::unsigned() - Deserialization happens automatically when accessing
getDisabled() - String and boolean values are not affected by serialization
Type Hints
All methods include proper PHP 8.2+ type hints:
disabled(string|bool|Closure $messageOrCallback = true): RoutegetDisabled(): string|bool|Closure|null- Full PHPDoc annotations for IDE support
License
The MIT License (MIT). Please see License File for more information.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Changelog
Please see CHANGELOG.md for more information on what has changed recently.