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
| Path | Page | Description |
|---|---|---|
/ | Dashboard | Overview with recent activity |
/collections/{slug} | Collection list | Filterable, sortable document list |
/collections/{slug}/create | Create document | New document form |
/collections/{slug}/{id} | Edit document | Document editor with sidebar |
/collections/{slug}/{id}/versions | Version history | Compare and restore versions |
/globals/{slug} | Global editor | Singleton document editor |
/settings | Settings index | Admin settings overview |
/settings/users | User management | List and manage users |
/settings/users/{id} | User detail | Edit user roles and scopes |
/settings/roles | Role management | List and manage roles |
/settings/roles/{id} | Role detail | Edit role permissions |
/settings/webhooks | Webhooks | List and manage webhooks |
/settings/webhooks/create | Create webhook | New webhook form |
/settings/webhooks/{id} | Edit webhook | Webhook configuration |
/settings/diagnostics | Schema diagnostics | Admin metadata health check |
/settings/audit-log | Audit log | System-wide activity log |
/login | Login page | Authentication page |
/api/vextro/cache/invalidate | API | Cache invalidation endpoint (POST) |
/api/vextro/cache/stats | API | Cache 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
| Option | Type | Default | Description |
|---|---|---|---|
apiImport | string | required | Import path for the Convex API module. |
adminFile | string | "convex/admin.ts" | Path to admin file for codegen. |
injectRoutes | boolean | true | Auto-inject standard API routes. |
autoGenerate | boolean | true | Auto-generate admin exports on startup. |
Auto-injected routes
| Route | Purpose |
|---|---|
/api/admin/sidebar | Sidebar navigation data |
/api/admin/relationship | Relationship picker options |
/api/search | Global search |
/api/admin/versions | Version history data |
/api/admin/templates | Content templates |
/api/admin/token | Auth token endpoint |
/api/auth/[...path] | Auth proxy (better-auth) |
/api/vextro/cache/[...action] | Cache invalidation and stats |