This guide covers the routing system for frontend plugins in Checkstack.
Routes are defined in common packages using createRoutes, which establishes a contract between the common package (which defines the routes) and the frontend plugin (which provides the components).
// In your-plugin-common/src/routes.ts
import { createRoutes } from "@checkstack/common";
export const yourPluginRoutes = createRoutes("your-plugin", {
home: "/",
config: "/config",
detail: "/detail/:id", // Path parameters are supported
});
Export from your index:
// In your-plugin-common/src/index.ts
export { yourPluginRoutes } from "./routes";
Import the routes and use them with the route field:
// In your-plugin-frontend/src/index.tsx
import { createFrontendPlugin } from "@checkstack/frontend-api";
import { yourPluginRoutes, pluginMetadata } from "@checkstack/your-plugin-common";
import { HomePage } from "./pages/HomePage";
import { ConfigPage } from "./pages/ConfigPage";
import { DetailPage } from "./pages/DetailPage";
export default createFrontendPlugin({
metadata: pluginMetadata,
routes: [
{
route: yourPluginRoutes.routes.home,
element: <HomePage />,
},
{
route: yourPluginRoutes.routes.config,
element: <ConfigPage />,
accessRule: yourPluginAccess.manage,
},
{
route: yourPluginRoutes.routes.detail,
element: <DetailPage />,
},
],
});
Routes can be resolved using resolveRoute from @checkstack/common:
import { resolveRoute } from "@checkstack/common";
import { catalogRoutes } from "@checkstack/catalog-common";
// Simple route
const configPath = resolveRoute(catalogRoutes.routes.config);
// Returns: "/catalog/config"
// With parameters
const detailPath = resolveRoute(catalogRoutes.routes.systemDetail, { systemId: "abc-123" });
// Returns: "/catalog/system/abc-123"
import { usePluginRoute } from "@checkstack/frontend-api";
import { maintenanceRoutes } from "@checkstack/maintenance-common";
function MyComponent() {
const getRoute = usePluginRoute();
return (
<Link to={getRoute(maintenanceRoutes.routes.config)}>
Maintenances
</Link>
);
}
The plugin registry automatically validates that route pluginId matches the frontend plugin name. For example, if a plugin named maintenance-frontend registers a route with pluginId: "maintenence" (typo), an error is thrown:
❌ Route pluginId mismatch: route "maintenence.config" has pluginId "maintenence"
but plugin is "maintenance-frontend" (base: "maintenance")
This ensures consistency between common package definitions and frontend plugins.
All routes are automatically prefixed with /{pluginId}:
/config in plugin maintenance → /maintenance/config/ in plugin catalog → /catalog//system/:systemId in plugin catalog → /catalog/system/:systemIdDefine routes in common packages - This allows both frontend and backend to share route definitions.
Use resolveRoute for links - Instead of hardcoding paths, use resolveRoute to get the full path.
Use path parameters - Define dynamic segments with :paramName syntax for type-safe parameter substitution.
Export routes from common index - Make routes easily importable.