Custom Features
Features are plan-gated capabilities that you define in config/custom.php. Once registered, they automatically appear in the admin panel for toggling and plan assignment.
Registering a Feature
Add entries to the features array in config/custom.php:
// config/custom.php
'features' => [
'projects' => [
'label' => 'Projects',
'description' => 'Project management with statuses and comments',
],
'time_tracking' => [
'label' => 'Time Tracking',
'description' => 'Track time spent on tasks and projects',
],
],
Where Features Appear
- Admin → Settings → Features — Global toggle to enable or disable the feature across the entire platform
- Admin → Plans → Edit Plan — Per-plan entitlement checkbox so you can include the feature in specific plans (e.g., Pro and Enterprise only)
Gating Routes by Feature
Use the entitled middleware to restrict access to routes based on the organization's plan:
// routes/custom.php
Route::prefix('projects')
->middleware('entitled:projects')
->group(function () {
Route::get('/', [ProjectController::class, 'index']);
Route::post('/', [ProjectController::class, 'store']);
});
If the organization's plan does not include the projects feature, the middleware returns a 403 response with an upgrade prompt.
Gating Frontend Routes
In frontend/src/custom/routes.tsx, add the feature property:
export const customRoutes: CustomRoute[] = [
{
path: '/org/projects',
element: <ProjectsPage />,
feature: 'projects',
permission: 'view_projects',
},
]
Users on plans without the feature are redirected to the dashboard.
Checking Features in Code
You can also check feature entitlement programmatically in your controllers:
$org = $request->user()->activeOrganization();
if (!$org->hasFeature('projects')) {
return response()->json(['message' => 'Upgrade required.'], 403);
}