PluginsAdmin Control Panel

AdminCP Pages

Add plugin-owned AdminCP pages, navigation, permissions, and dashboard extensions to the VitNode admin panel.

AdminCP is a plugin surface. Give the plugin an area: 'admin' route and a browser-safe navigation declaration. The host supplies the panel shell; your plugin supplies the useful bit.

Claim an AdminCP route

plugins/site-notes/src/routes.ts
import { definePluginRoutes, lazy, page } from '@vitnode/core/routing'

export const routes = definePluginRoutes([
  page('/admin/site-notes/settings', {
    area: 'admin',
    component: lazy(() => import('./pages/admin-settings-page')),
  }),
])

Render the plugin page

plugins/site-notes/src/pages/admin-settings-page.tsx
const AdminSettingsPage = () => (
  <div className="flex flex-col gap-2 p-4">
    <h2 className="text-2xl font-semibold">Site notes settings</h2>
    <p className="text-muted-foreground">Manage the notes plugin.</p>
  </div>
)

export default AdminSettingsPage

Add a sidebar entry

Export adminNav from the plugin. Its small browser-safe shape is what the generated AdminCP registry imports—do not edit admin-nav.gen.ts yourself.

plugins/site-notes/src/admin/nav.tsx
import type { AdminNavPluginSource } from '@vitnode/core/lib/plugin'
import { SettingsIcon } from 'lucide-react'

export const adminNav = {
  pluginId: '@acme/site-notes',
  admin: {
    nav: [
      {
        href: '/admin/site-notes/settings',
        icon: <SettingsIcon />,
        id: 'settings',
        permission: { module: 'site_notes', permission: 'can_manage_settings' },
      },
    ],
  },
} satisfies AdminNavPluginSource

The generator’s ./* package export already exposes admin/nav; no manual package.json export is required, and nothing changes in config.tsx. The generated admin-nav.gen.ts imports admin/nav directly, and keeping the factory to plain data is what keeps the sidebar registration out of every public page's bundle.

Verify the screen

Run the AdminCP extension
bun dev

Visit http://localhost:3000/admin/site-notes/settings as a staff account with the declared permission.

Extend the panel