> ## Documentation Index
> Fetch the complete documentation index at: https://docs.corsair.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Frameworks

> Mount the Corsair /api/corsair route on your framework — Next.js, Express, Hono, or any Web-standard runtime.

Corsair mounts **one** route. It serves Hub delivery — OAuth callbacks, connect pages, self-registration — and the [management API](/management/handler) in the same place. Every adapter wraps a single primitive, `managementHandler(corsair)`, which returns a `(request: Request) => Promise<Response>`. Pick the tab for your server; the rest of your app is identical.

## Configure Corsair

```ts corsair.ts theme={null}
import { createCorsair } from 'corsair';
import { github } from '@corsair-dev/github';

export const corsair = createCorsair({
    plugins: [github({ authType: 'managed' })],
    database: db,
    kek: process.env.CORSAIR_KEK!,
    hub: {
        projectApiKey: process.env.CORSAIR_DEV_API_KEY!,
        signingSecret: process.env.CORSAIR_DEV_SIGNING_SECRET!,
    },
});
```

## Mount the route

<Tabs>
  <Tab title="Next.js">
    ```ts app/api/corsair/[[...path]]/route.ts theme={null}
    import { toNextJsHandler } from 'corsair';
    import { corsair } from '@/server/corsair';

    export const { GET, POST, OPTIONS } = toNextJsHandler(corsair, {
        basePath: '/api/corsair',
    });
    ```

    <Note>Pages Router? Export a catch-all API route at `pages/api/corsair/[...path].ts` and forward `req`/`res` through the same `toNextJsHandler`. The App Router is the supported default.</Note>
  </Tab>

  <Tab title="Express">
    ```ts server.ts theme={null}
    import express from 'express';
    import { toExpressHandler } from 'corsair';
    import { corsair } from './corsair';

    const app = express();

    // Required: Hub delivers results as JSON POSTs. The adapter reads the parsed
    // body, so express.json() must run before the Corsair route.
    app.use(express.json());
    app.use('/api/corsair', toExpressHandler(corsair, { basePath: '/api/corsair' }));

    app.listen(3000);
    ```

    <Warning>Mount `express.json()` **before** the Corsair route. Without it, `req.body` is undefined and Hub's delivery POSTs arrive empty — connects will look like they hang.</Warning>
  </Tab>

  <Tab title="Hono">
    ```ts index.ts theme={null}
    import { Hono } from 'hono';
    import { toHonoHandler } from 'corsair';
    import { corsair } from './corsair';

    const app = new Hono();

    // Wildcard: Corsair routes several paths under the base (delivery, connect,
    // tenants). Match them all with `/*`, and keep basePath in sync with the mount.
    app.all('/api/corsair/*', toHonoHandler(corsair, { basePath: '/api/corsair' }));

    export default app;
    ```
  </Tab>

  <Tab title="Web-standard">
    Every adapter wraps one primitive: `managementHandler(corsair)` returns `(request: Request) => Promise<Response>`. Any framework whose routes speak the Fetch API calls it directly — no adapter needed.

    <CodeGroup>
      ```ts SvelteKit theme={null}
      // src/routes/api/corsair/[...path]/+server.ts
      import { managementHandler } from 'corsair';
      import { corsair } from '$lib/server/corsair';

      const handler = managementHandler(corsair, { basePath: '/api/corsair' });
      export const GET = ({ request }) => handler(request);
      export const POST = ({ request }) => handler(request);
      ```

      ```ts Remix theme={null}
      // app/routes/api.corsair.$.ts
      import { managementHandler } from 'corsair';
      import { corsair } from '~/server/corsair';

      const handler = managementHandler(corsair, { basePath: '/api/corsair' });
      export const loader = ({ request }) => handler(request);
      export const action = ({ request }) => handler(request);
      ```

      ```ts Astro theme={null}
      // src/pages/api/corsair/[...path].ts
      import { managementHandler } from 'corsair';
      import { corsair } from '../../../server/corsair';

      const handler = managementHandler(corsair, { basePath: '/api/corsair' });
      export const GET = ({ request }) => handler(request);
      export const POST = ({ request }) => handler(request);
      export const prerender = false;
      ```

      ```ts Nuxt theme={null}
      // server/routes/api/corsair/[...path].ts
      import { fromWebHandler } from 'h3';
      import { managementHandler } from 'corsair';
      import { corsair } from '~/server/corsair';

      // h3's fromWebHandler adapts the (Request) => Response handler to Nitro.
      export default fromWebHandler(
          managementHandler(corsair, { basePath: '/api/corsair' }),
      );
      ```

      ```ts Workers / Bun / Deno theme={null}
      import { managementHandler } from 'corsair';
      import { corsair } from './corsair';

      const handler = managementHandler(corsair, { basePath: '/api/corsair' });
      export default { fetch: (request: Request) => handler(request) };
      ```
    </CodeGroup>

    <Note>Backend not in JavaScript? Corsair's SDK is TypeScript-only. Integrate over the [Hub REST API](/hub/rest-api) instead.</Note>
  </Tab>
</Tabs>

## Run and go green

Start your dev server and make one request to `/api/corsair`. On that first request your app self-registers its delivery URL with Hub and the dashboard header dot turns green. See [Delivery URLs](/hub/delivery-urls).

Stays grey? The route isn't reachable at `/api/corsair`. Check the mount path and — on Express and Hono — that `basePath` and the wildcard (`/api/corsair/*`) match the path you mounted.

## What's next

<CardGroup cols={2}>
  <Card title="Hub setup" href="/hub/setup">Create a project, copy keys, reach the green check.</Card>
  <Card title="Add a plugin" href="/guides/plugins">Browse the catalog — GitHub, Slack, Linear, and hundreds more.</Card>
  <Card title="Vanilla client" href="/adapters/client">Call the management API from any JS runtime.</Card>
  <Card title="React hooks" href="/adapters/react">Typed `useTenants`, `useConnectionStatus`, and friends.</Card>
</CardGroup>
