Fix: Payload URL Must Not Include Hostname in Nuxt

Error message:
Payload URL must not include hostname: {url}
ssr 2025-01-25

What Causes This Error?

This error occurs when you configure a payload URL that includes a full hostname (like https://example.com/...) instead of a relative path. Nuxt payloads should use relative URLs.

The Problem

// nuxt.config.ts
export default defineNuxtConfig({
  // ❌ Wrong - includes hostname
  app: {
    cdnURL: 'https://cdn.example.com/'
  },

  // When this generates payload URLs like:
  // https://cdn.example.com/_payload.json
  // instead of:
  // /_payload.json
})

The Fix

Use Relative Paths

// nuxt.config.ts
export default defineNuxtConfig({
  // ✅ Correct - relative paths
  app: {
    baseURL: '/',
    cdnURL: '/'  // Or omit entirely
  }
})

Configure CDN at Server Level

Instead of configuring CDN URL in Nuxt, handle it at the server/proxy level:

# nginx.conf
location /_nuxt/ {
    proxy_pass https://cdn.example.com/_nuxt/;
}

location /_payload.json {
    # Serve payloads locally or proxy
    try_files $uri @backend;
}

Understanding Payload URLs

What Are Payloads?

Payloads contain serialized data from SSR that the client uses for hydration:

your-site.com/
├── _payload.json          ← Root payload
├── products/
│   └── _payload.json      ← Products page payload
└── about/
    └── _payload.json      ← About page payload

Why Relative URLs?

  1. Security: Prevents cross-origin issues
  2. Flexibility: Works regardless of deployment domain
  3. Simplicity: No CORS configuration needed

Common Scenarios

Using a CDN

// ❌ Wrong - absolute URL
export default defineNuxtConfig({
  app: {
    cdnURL: 'https://cdn.example.com'
  }
})

// ✅ Correct - let CDN handle routing
export default defineNuxtConfig({
  app: {
    baseURL: '/'
  },

  nitro: {
    // Configure CDN for static assets only
    publicAssets: [{
      baseURL: '/_nuxt/',
      dir: '.output/public/_nuxt'
    }]
  }
})

CDN for Assets Only

Keep payloads on origin, serve assets from CDN:

// nuxt.config.ts
export default defineNuxtConfig({
  // Assets can use CDN
  $production: {
    app: {
      cdnURL: process.env.CDN_URL || '/'
    }
  },

  // But payloads stay relative
  experimental: {
    payloadExtraction: true
  }
})

CDN configuration (Cloudflare/Nginx):

# Serve /_nuxt/* from CDN
location /_nuxt/ {
    proxy_pass https://cdn.example.com/_nuxt/;
    expires 1y;
}

# Keep payloads on origin
location ~ /_payload\.json$ {
    expires 1h;
    try_files $uri =404;
}

Multi-Domain Setup

// nuxt.config.ts
export default defineNuxtConfig({
  app: {
    // Keep relative
    baseURL: '/'
  },

  routeRules: {
    // Handle different domains in route rules
    '/api/**': {
      proxy: { to: 'https://api.example.com/**' }
    }
  }
})

Fixing Existing Issues

Check Your Configuration

// Look for absolute URLs in:
export default defineNuxtConfig({
  app: {
    baseURL: '/',           // Should be relative
    cdnURL: '/',            // Should be relative or omitted
    buildAssetsDir: '/_nuxt/'  // Should be relative
  }
})

Remove Hostname from CDN URL

// ❌ Before
cdnURL: 'https://cdn.example.com/'

// ✅ After
cdnURL: '/'

// Or handle via environment
cdnURL: process.env.NODE_ENV === 'production'
  ? '/'  // Use proxy/CDN configuration instead
  : '/'

Alternative: Custom Payload Handler

// nuxt.config.ts
export default defineNuxtConfig({
  hooks: {
    'build:manifest'(manifest) {
      // Modify manifest to use relative URLs
      // This is advanced usage
    }
  }
})

Debugging

Check Generated URLs

# Build and check output
npm run build

# Look at generated HTML
cat .output/public/index.html | grep payload

Verify Payload Requests

In browser DevTools:

  1. Open Network tab
  2. Navigate to a page
  3. Filter by _payload
  4. Check the request URL is relative

Environment-Specific Configuration

// nuxt.config.ts
export default defineNuxtConfig({
  $development: {
    app: {
      baseURL: '/'
    }
  },

  $production: {
    app: {
      baseURL: process.env.BASE_URL || '/'
    }
  }
})

Quick Checklist

  • app.cdnURL is relative or omitted
  • app.baseURL is relative (e.g., / or /app/)
  • No full URLs (https://…) in payload-related config
  • CDN routing configured at server/proxy level
  • Payloads served from same origin as HTML
  • CORS not required for payload fetching