---
title: Vercel
description: Use Vercel rewrites to proxy documentation requests to Jamdesk. Rewrites happen at the edge and don't change the URL in the browser.
---

> **For AI agents:** the complete documentation index is at [llms.txt](/docs/llms.txt). Append `.md` to any page URL for its markdown version.

If your site is already deployed on Vercel, two rewrite rules in `vercel.json` (or `next.config.js`) are enough to serve Jamdesk docs at `/docs` -- no separate proxy or DNS changes needed. For custom domain verification, an Edge Middleware approach is also covered below.

## Prerequisites

- A project deployed on Vercel
- Your Jamdesk subdomain (found in dashboard settings)

## Step 1: Update vercel.json

Add a `rewrites` configuration to your `vercel.json` file. If the file doesn't exist, create it in your project root:

```json vercel.json
{
  "rewrites": [
    {
      "source": "/docs",
      "destination": "https://YOUR_SLUG.jamdesk.app/docs"
    },
    {
      "source": "/docs/:path*",
      "destination": "https://YOUR_SLUG.jamdesk.app/docs/:path*"
    },
    {
      "source": "/_next/:path*",
      "destination": "https://YOUR_SLUG.jamdesk.app/_next/:path*"
    },
    {
      "source": "/_jd/:path*",
      "destination": "https://YOUR_SLUG.jamdesk.app/_jd/:path*"
    }
  ]
}
```

<Note>
Replace `YOUR_SLUG` with your actual Jamdesk subdomain (e.g., `acme` if your docs are at `acme.jamdesk.app`).
</Note>

The `/_next/` and `/_jd/` rewrites are required for Next.js assets (JS, CSS) and Jamdesk resources (fonts, images, branding) to load correctly.

## Step 2: Deploy

Deploy your changes to Vercel:

```bash
vercel --prod
```

Or push to your connected Git repository to trigger an automatic deployment.

## Step 3: Verify

Visit `https://yoursite.com/docs` to confirm your documentation is being served correctly.

## Understanding the Configuration

| Property | Description |
|----------|-------------|
| `source` | The path pattern on your domain that triggers the rewrite |
| `destination` | The URL to proxy the request to |
| `:path*` | A wildcard that captures all path segments after `/docs/` |

The rewrite rules handle:
1. The base `/docs` path (e.g., `yoursite.com/docs`)
2. All nested paths (e.g., `yoursite.com/docs/getting-started`)
3. Next.js static assets (`/_next/`) and Jamdesk resources (`/_jd/`)

## Adding to Existing Rewrites

If you already have rewrites configured, add the Jamdesk rules to your existing array:

```json vercel.json
{
  "rewrites": [
    { "source": "/api/:path*", "destination": "/api/:path*" },
    { "source": "/docs", "destination": "https://YOUR_SLUG.jamdesk.app/docs" },
    { "source": "/docs/:path*", "destination": "https://YOUR_SLUG.jamdesk.app/docs/:path*" },
    { "source": "/_next/:path*", "destination": "https://YOUR_SLUG.jamdesk.app/_next/:path*" },
    { "source": "/_jd/:path*", "destination": "https://YOUR_SLUG.jamdesk.app/_jd/:path*" }
  ]
}
```

<Warning>
Rewrite order matters. Place more specific rules before general ones.
</Warning>

## Using next.config.js (Next.js Projects)

For Next.js projects, you can alternatively configure rewrites in `next.config.js`:

```javascript next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  async rewrites() {
    return [
      {
        source: "/docs",
        destination: "https://YOUR_SLUG.jamdesk.app/docs",
      },
      {
        source: "/docs/:path*",
        destination: "https://YOUR_SLUG.jamdesk.app/docs/:path*",
      },
      {
        source: "/_next/:path*",
        destination: "https://YOUR_SLUG.jamdesk.app/_next/:path*",
      },
      {
        source: "/_jd/:path*",
        destination: "https://YOUR_SLUG.jamdesk.app/_jd/:path*",
      },
    ];
  },
};

export default nextConfig;
```

## Troubleshooting

<Accordion title="Rewrites not working">
Ensure `vercel.json` is in your project root and properly formatted. Check the Vercel deployment logs for configuration errors.
</Accordion>

<Accordion title="404 on nested pages">
Verify you have both rewrite rules - one for `/docs` and one for `/docs/:path*`. Missing the wildcard rule causes nested pages to fail.
</Accordion>

<Accordion title="Infinite redirect loops">
Check that your destination URL uses `https://` and points to `jamdesk.app`, not your own domain.
</Accordion>

<Accordion title="Assets not loading (broken styles, missing fonts)">
Check that you have rewrite rules for both `/_next/:path*` and `/_jd/:path*`. These serve Next.js assets (JS, CSS) and Jamdesk resources (fonts, images). Missing either breaks the layout.
</Accordion>

<Accordion title="403 Domain not authorized error">
When using Edge Middleware with a custom domain:

1. Verify your domain is registered in the Jamdesk dashboard
2. Complete DNS verification (TXT record)
3. Confirm the `X-Jamdesk-Forwarded-Host` header is set in your middleware
4. Check the domain maps to the correct project

Simple rewrites (no custom domain) don't need this header.
</Accordion>

## Custom Domain Verification

Vercel rewrites work by proxying requests to your Jamdesk subdomain (`YOUR_SLUG.jamdesk.app`). This basic setup doesn't require domain verification.

If you've configured a custom domain in the Jamdesk dashboard with the "Host at /docs" option, you'll need to use Edge Middleware instead of simple rewrites to set the required verification header.

### How It Works

The middleware forwards requests to your Jamdesk subdomain while passing along the original domain in the `X-Jamdesk-Forwarded-Host` header. Jamdesk uses this header to:

1. **Verify your domain** - Ensures only authorized domains can serve your docs
2. **Apply correct configuration** - Uses your domain's settings from the dashboard

This means the middleware is a **one-time setup**. If you later change your custom domain or configuration in the Jamdesk dashboard, the middleware doesn't need to be updated - all routing decisions are made server-side.

### Using Edge Middleware

Create a `middleware.ts` file in your project root:

```typescript middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

const JAMDESK_HOST = 'YOUR_SLUG.jamdesk.app';

export function middleware(request: NextRequest) {
  const url = request.nextUrl;

  // Only proxy /docs and asset paths
  if (!url.pathname.startsWith('/docs') &&
      !url.pathname.startsWith('/_next') &&
      !url.pathname.startsWith('/_jd')) {
    return NextResponse.next();
  }

  // Rewrite to Jamdesk with forwarded host header
  const destination = new URL(url.pathname + url.search, `https://${JAMDESK_HOST}`);

  // Clone headers and add the forwarded host
  const headers = new Headers(request.headers);
  headers.set('X-Jamdesk-Forwarded-Host', url.hostname);

  return NextResponse.rewrite(destination, {
    request: { headers },
  });
}

export const config = {
  matcher: ['/docs', '/docs/:path*', '/_next/:path*', '/_jd/:path*'],
};
```

<Note>
Replace `YOUR_SLUG` with your actual Jamdesk subdomain.
</Note>

<Warning>
The `X-Jamdesk-Forwarded-Host` header is **required**. It enables:
- Domain verification (your domain must be registered in the dashboard)
- Correct URL generation for links and assets
- Proper configuration from your dashboard settings

Without this header, requests will be rejected with a 403 error.
</Warning>

### When to Use Middleware vs Rewrites

| Approach | Use When |
|----------|----------|
| **Rewrites** | Basic setup without custom domain verification |
| **Edge Middleware** | Custom domain with "Host at /docs" option enabled |

If you don't need custom domain verification, the simpler rewrites approach is sufficient.

## What's Next?

<Columns cols={3}>
  <Card title="Deployment Overview" icon="cloud-arrow-up" href="/deploy/overview">
    Compare hosting options
  </Card>
  <Card title="Subpath Hosting" icon="folder-tree" href="/deploy/subpath-hosting">
    Serve docs at /docs
  </Card>
  <Card title="Custom Domains" icon="globe" href="/deploy/custom-domains">
    Verify DNS and troubleshoot
  </Card>
</Columns>
