Alkademi Logo
Plugin System

Plugin System

A plugin is an additional Nuxt Layer placed under plugins/. Plugins are used to add new features, replace selected cores, or enrich navigation without changing source files under cores/.

Plugin System

A plugin is an additional Nuxt Layer placed under plugins/. Plugins are used to add new features, replace selected cores, or enrich navigation without changing source files under cores/.

Plugin Structure

plugins/my-plugin/
|-- components/          # Plugin components
|-- pages/               # Plugin pages
|-- server/api/          # Plugin Nitro endpoints, when needed
|-- stores/              # Plugin Pinia stores, when needed
|-- plugin.config.ts     # Plugin configuration
|-- sidebar.ts           # Optional: dynamic sidebar menu provider
`-- nuxt.config.ts       # Marks the plugin as a Nuxt Layer

The required files for auto-discovery are nuxt.config.ts and plugin.config.ts.

Current Plugin Configuration

The plugin contract follows PluginConfig in shared/types/plugin.ts. The main fields currently used are:

  • enabled: determines whether the plugin is active.
  • routes: route definitions that also become static sidebar menu items.
  • replaces: optional list of core ids to replace.

Example:

import type { PluginConfig } from '../../shared/types/plugin'

export default {
  enabled: true,
  replaces: ['program'],
  routes: [
    {
      key: 'custom-class',
      path: '/dashboard/custom-class',
      icon: 'i-heroicons-sparkles',
      label: 'Custom Class'
    }
  ]
} satisfies PluginConfig

The current project does not use name, displayName, version, overrideMode, or targetCore as the primary plugin contract.

Routes and Sidebar

Each item in routes must have:

  • path: the dashboard URL.
  • icon: a Nuxt UI/Iconify icon name, for example i-heroicons-sparkles.
  • label: the menu label.

Supported optional fields:

  • key: a stable id for menu merging.
  • children: child menu items.
  • permission: a single permission or an array of permissions.
  • meta: custom metadata.

routes is used by useSidebarMenu() to create static menu items. If a plugin needs dynamic menu items, add sidebar.ts.

Dynamic Sidebar

A plugin can provide sidebar.ts that exports a sidebar provider:

import { defineSidebarProvider } from '../../shared/types/menu'

export default defineSidebarProvider(async ({ route }) => {
  if (!route.path.startsWith('/dashboard/custom-class')) {
    return []
  }

  const classes = await $fetch('/api/custom-class/sidebar')

  return [
    {
      key: 'custom-class',
      path: '/dashboard/custom-class',
      icon: 'i-heroicons-sparkles',
      label: 'Custom Class',
      source: 'plugin',
      pluginId: 'custom-class',
      children: classes.map((item) => ({
        key: `custom-class.${item.id}`,
        path: `/dashboard/custom-class/${item.id}`,
        icon: 'i-heroicons-document-text',
        label: item.label,
        source: 'plugin',
        pluginId: 'custom-class'
      }))
    }
  ]
})

Menu items from sidebar.ts are merged with static menu items by key or path.


Learn about replacement behavior in Override System.

Copyright © 2026