Configuration

Routing

Vextro uses Astro's file-based routing with a catchall route to serve all admin pages from a single entry point. This page explains how to set it up, the complete route table, and how to break out of the catchall for custom pages.

Setting up the catchall

Create a [...vextro].astro page in your admin app:

---
// src/pages/[...vextro].astro
import { VextroCatchallPage } from "vextro/astro";
import { handleVextroCatchallRequest } from "vextro/astro/catchall";
import AdminLayout from "../layouts/AdminLayout.astro";

// Handle API routes and POST requests before rendering
const apiResponse = await handleVextroCatchallRequest({
  request: Astro.request,
  params: Astro.params,
  basePath: "",
  locals: Astro.locals,
  cookies: Astro.cookies,
  redirect: Astro.redirect,
  convex: Astro.locals.convex,
  api: (await import("virtual:vextro/convex-api")).api,
});
if (apiResponse) return apiResponse;
---

<AdminLayout>
  <VextroCatchallPage
    params={Astro.params}
    request={Astro.request}
    locals={Astro.locals}
    basePath=""
  />
</AdminLayout>

Route segment structure

Routes follow the pattern /{section}/{slug}/{id} where:

  • section — the page type (e.g., collections, globals, settings)
  • slug — the collection or global slug
  • id — document ID (for edit pages)

Complete route table

PathPageDescription
/DashboardOverview with recent activity
/collections/{slug}Collection listFilterable, sortable document list
/collections/{slug}/createCreate documentNew document form
/collections/{slug}/{id}Edit documentDocument editor with sidebar
/collections/{slug}/{id}/versionsVersion historyCompare and restore versions
/globals/{slug}Global editorSingleton document editor
/settingsSettings indexAdmin settings overview
/settings/usersUser managementList and manage users
/settings/users/{id}User detailEdit user roles and scopes
/settings/rolesRole managementList and manage roles
/settings/roles/{id}Role detailEdit role permissions
/settings/webhooksWebhooksList and manage webhooks
/settings/webhooks/createCreate webhookNew webhook form
/settings/webhooks/{id}Edit webhookWebhook configuration
/settings/diagnosticsSchema diagnosticsAdmin metadata health check
/settings/audit-logAudit logSystem-wide activity log
/loginLogin pageAuthentication page
/api/vextro/cache/invalidateAPICache invalidation endpoint (POST)
/api/vextro/cache/statsAPICache stats endpoint (GET)

handleVextroCatchallRequest

This function intercepts API routes and POST requests before the page renders:

type HandleVextroCatchallArgs = {
  request: Request;
  params: Record<string, string | undefined>;
  basePath?: string;
  site?: URL;
  clientAddress?: string;
  locals?: Record<string, unknown>;
  cookies?: unknown;
  redirect?: (path: string, status?: RedirectStatus) => Response;
  convex?: any;
  api?: any;
};

API routes (auth proxy, cache management) are handled by dedicated .ts endpoint files injected automatically by the Vextro integration — they never reach this function. The catch-all only handles:

  • Page-level POST requests (document mutations)

Returns Response | null — when null, the page should render normally.

basePath configuration

If your admin lives at a subpath (e.g., /admin), set basePath:

// VextroConfig
const config: VextroConfig = {
  brandName: "My App",
  basePath: "/admin",
};

Then in your catchall and middleware, use the same basePath.

Breaking out of the catchall

Custom pages with the Vextro shell

Create a specific Astro file — it takes priority over the catchall. Use VextroShellLayout to keep the sidebar and header:

---
// src/pages/custom-dashboard.astro
import VextroShellLayout from "vextro/components/VextroShellLayout.astro";
import { api } from "../convex/_generated/api";
import { adminConfig } from "../config/admin";

const convex = Astro.locals.convex;
---

<VextroShellLayout config={adminConfig} convex={convex} api={api}>
  <div class="p-space-6">
    <h1 class="text-2xl font-semibold text-fg">Custom Dashboard</h1>
    <!-- Your custom content -->
  </div>
</VextroShellLayout>

Pass the authenticated, request-scoped Convex client and generated API object on standalone shell pages. The shell uses them for access-filtered navigation and reactive features such as global search.

Custom pages without the shell

Create a standalone Astro page with no Vextro layout:

---
// src/pages/standalone.astro
---
<html>
  <body>
    <h1>Standalone Page</h1>
  </body>
</html>

Custom API endpoints

Add API routes alongside the catchall using standard Astro file-based routing:

// src/pages/api/custom/my-endpoint.ts
import type { APIRoute } from "astro";

export const POST: APIRoute = async ({ request, locals }) => {
  const data = await request.json();
  // Your custom logic
  return new Response(JSON.stringify({ ok: true }), {
    headers: { "Content-Type": "application/json" },
  });
};

API routes like auth and cache are handled by dedicated endpoints injected via the Vextro integration — you don't need to wire them up manually. Use standard Astro file-based routing for any custom API endpoints.

Astro integration

The createVextroIntegration auto-injects standard API routes and sets up the Convex API virtual module:

// astro.config.mjs
import { createVextroIntegration } from "vextro/astro/integration";

export default defineConfig({
  integrations: [
    createVextroIntegration({
      apiImport: "@myapp/convex/_generated/api",
    }),
  ],
});

Integration options

OptionTypeDefaultDescription
apiImportstringrequiredImport path for the Convex API module.
adminFilestring"convex/admin.ts"Path to admin file for codegen.
injectRoutesbooleantrueAuto-inject standard API routes.
autoGeneratebooleantrueAuto-generate admin exports on startup.

Auto-injected routes

RoutePurpose
/api/admin/sidebarSidebar navigation data
/api/admin/relationshipRelationship picker options
/api/searchGlobal search
/api/admin/versionsVersion history data
/api/admin/templatesContent templates
/api/admin/tokenAuth token endpoint
/api/auth/[...path]Auth proxy (better-auth)
/api/vextro/cache/[...action]Cache invalidation and stats
Previous
Convex Component
Next
Overview