How to Add a New Route in Celeris Web Using Vue Router

Developers add new routes in Celeris Web by creating a TypeScript module under apps/admin/src/router/routes/modules/ that exports a RouteRecordRaw object, which is automatically glob-imported and registered via the permission guard.

Celeris Web, the Vue 3 admin framework in the kirklin/celeris-web repository, uses a file-based routing convention that eliminates manual route registration. Instead of editing a central router configuration, you create declarative route modules that the build system discovers automatically.

Understanding the Route Architecture

Celeris Web separates routes into two categories to handle authentication and code splitting efficiently.

basicRoutes are static routes always available at startup. These include the login page, root redirects, and 404 handlers defined in apps/admin/src/router/routes/index.ts.

asyncRoutes are dynamically loaded from the modules/ directory. These routes are discovered at build time using import.meta.glob, processed by the loadRoutesFromModules utility, and registered only after the user authenticates via the permission guard in apps/admin/src/router/guard/permissionGuard.ts.

Creating a New Route Module

To add a new route, create a TypeScript file in the modules directory that exports a default RouteRecordRaw configuration.

Step 1: Create the Route File

Create a new file at apps/admin/src/router/routes/modules/[feature-name].ts. For example, to add a reports section:

import type { RouteRecordRaw } from "vue-router";
import { LAYOUT } from "~/router/constant";

const reports: RouteRecordRaw = {
  path: "/reports",
  name: "ReportsRoot",
  component: LAYOUT,
  redirect: "/reports/summary",
  meta: {
    title: "routes.reports.title",
    icon: "i-mdi-file-chart",
    orderNumber: 100,
  },
  children: [
    {
      path: "summary",
      name: "ReportsSummary",
      component: () => import("~/pages/reports/summary.vue"),
      meta: {
        title: "routes.reports.summary",
        icon: "i-mdi-chart-pie",
      },
    },
    {
      path: "detail/:id",
      name: "ReportDetail",
      component: () => import("~/pages/reports/detail.vue"),
      meta: {
        title: "routes.reports.detail",
        shouldHideInMenu: true,
      },
    },
  ],
};

export default reports;

Step 2: Define Meta Properties for the Menu

The meta object controls how the route appears in the navigation sidebar managed by packages/web/utils/src/menuHelper.ts:

  • title: The display label (typically an i18n key).
  • icon: The icon class for the sidebar.
  • orderNumber: Controls the sort order in the menu.
  • shouldHideInMenu: Set to true to exclude the route from the sidebar.
  • shouldAffixToNavBar: Pins the route to the top navigation bar.

How Automatic Route Discovery Works

The routing system uses Vite's import.meta.glob to collect all route modules without manual imports.

In apps/admin/src/router/routes/index.ts, the system executes:

const modules = import.meta.glob("./modules/**/*.ts", { eager: true });

The loadRoutesFromModules function in packages/web/utils/src/router.ts then transforms this glob map into a clean array of RouteRecordRaw objects. This design means any new file placed under apps/admin/src/router/routes/modules/ (including subdirectories) is instantly part of the asyncRoutes collection at build time.

Registering Routes at Runtime

While file-based routes cover most use cases, you can also register routes dynamically after the application starts.

The permission guard in apps/admin/src/router/guard/permissionGuard.ts demonstrates the standard pattern for adding async routes after authentication:

asyncRoutes.forEach((route) => {
  router.addRoute(route);
});

For user-specific routes fetched from an API, the user store in apps/admin/src/store/modules/user.ts shows how to add routes on the fly:

import { router } from "~/router";

const dynamicRoute: RouteRecordRaw = {
  path: "/custom/:slug",
  name: "CustomPage",
  component: () => import("~/pages/custom/index.vue"),
  meta: { requiresAuth: true },
};

router.addRoute(dynamicRoute);

Key Files Reference

File Purpose
apps/admin/src/router/routes/index.ts Defines basicRoutes and loads all module routes via glob import.
apps/admin/src/router/routes/modules/*.ts Individual route definitions (e.g., dashboard.ts).
packages/web/utils/src/router.ts Contains loadRoutesFromModules for processing globbed routes.
apps/admin/src/router/guard/permissionGuard.ts Registers asyncRoutes using router.addRoute after login.
packages/web/utils/src/menuHelper.ts Builds the sidebar navigation from route meta fields.

Summary

  • Create a TypeScript file under apps/admin/src/router/routes/modules/ exporting a default RouteRecordRaw object.
  • Export the route configuration as the default export so the glob loader can parse it correctly.
  • Control sidebar visibility using meta properties like shouldHideInMenu and orderNumber.
  • Register routes automatically through the file system, or manually via router.addRoute() for dynamic permissions.
  • Modify packages/web/utils/src/menuHelper.ts logic only if you need custom menu filtering beyond the standard meta fields.

Frequently Asked Questions

Where do I place new route definitions in Celeris Web?

Place all new route definitions as TypeScript files inside apps/admin/src/router/routes/modules/. The system recursively scans this directory using import.meta.glob, so files in subfolders are also discovered automatically.

How does Celeris Web automatically discover new routes?

The router initialization in apps/admin/src/router/routes/index.ts uses Vite's import.meta.glob("./modules/**/*.ts") to eagerly import all module files at build time. The loadRoutesFromModules utility in packages/web/utils/src/router.ts then converts these imports into the asyncRoutes array without requiring manual imports.

Can I add routes dynamically after the app starts?

Yes. Use the router.addRoute() method from Vue Router as demonstrated in apps/admin/src/store/modules/user.ts. This is useful for registering user-specific routes returned from an API after authentication, though most static features should use the file-based approach for better type safety and code splitting.

How do I hide a route from the sidebar navigation?

Set meta.shouldHideInMenu = true in your route definition. The menu helper in packages/web/utils/src/menuHelper.ts filters out routes with this flag when building the sidebar navigation tree. You can also use meta.shouldAffixToNavBar = true to show the route in the top navigation instead.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →