Fix: Server Components with ssr:false Not Supported in Nuxt

Error message:
Server components are not supported with `ssr: false`.
ssr 2025-01-25

What Causes This Warning?

This warning appears when you try to use server components (.server.vue files) while having SSR disabled in your Nuxt configuration. Server components require server-side rendering to function.

The Problem

// nuxt.config.ts
export default defineNuxtConfig({
  ssr: false,  // SSR disabled
  experimental: {
    componentIslands: true  // ❌ Conflict!
  }
})
<!-- components/HeavyData.server.vue -->
<!-- ❌ Won't work with ssr: false -->
<template>
  <div>Server-rendered content</div>
</template>

The Fix

Option 1: Enable SSR

// nuxt.config.ts
export default defineNuxtConfig({
  ssr: true,  // Enable SSR
  experimental: {
    componentIslands: true  // ✅ Now works
  }
})

Option 2: Don’t Use Server Components

// nuxt.config.ts
export default defineNuxtConfig({
  ssr: false,  // Keep SSR disabled
  // Don't use componentIslands
})

Rename server components:

components/
├── HeavyData.server.vue  → HeavyData.vue
└── Stats.server.vue      → Stats.vue

Option 3: Use Route-Specific SSR

// nuxt.config.ts
export default defineNuxtConfig({
  ssr: true,  // Enable globally

  routeRules: {
    // Disable SSR only for specific routes
    '/admin/**': { ssr: false },
    '/dashboard/**': { ssr: false }
  },

  experimental: {
    componentIslands: true
  }
})

Understanding the Conflict

What Server Components Do

<!-- components/Data.server.vue -->
<script setup>
// This runs ONLY on the server
const data = await $fetch('https://api.example.com/heavy-data')
</script>

<template>
  <!-- Rendered on server, sent as HTML -->
  <div>{{ data }}</div>
</template>

Why ssr: false Breaks It

With ssr: false:

  1. No server-side rendering happens
  2. Everything runs in the browser
  3. .server.vue files have nowhere to run

Alternative Patterns

For ssr: false Apps

Use client-side fetching instead:

<!-- components/Data.vue (not .server.vue) -->
<script setup>
// Fetches on client
const { data, pending } = await useFetch('/api/data')
</script>

<template>
  <div v-if="pending">Loading...</div>
  <div v-else>{{ data }}</div>
</template>

Lazy Loading Heavy Components

<!-- pages/index.vue -->
<template>
  <!-- Lazy load without server components -->
  <LazyHeavyChart v-if="showChart" />
</template>

<script setup>
const showChart = ref(false)

onMounted(() => {
  // Load after initial render
  showChart.value = true
})
</script>

Use ClientOnly Wrapper

<template>
  <ClientOnly>
    <HeavyComponent />
    <template #fallback>
      <LoadingSpinner />
    </template>
  </ClientOnly>
</template>

Hybrid Approach

Keep SSR but disable for specific pages:

<!-- pages/spa-page.vue -->
<script setup>
// This page is SPA-only
definePageMeta({
  ssr: false
})
</script>

<template>
  <!-- Client-side only content -->
  <div>This page doesn't use SSR</div>
</template>

Server components work on other pages:

<!-- pages/ssr-page.vue -->
<template>
  <!-- Server components work here -->
  <HeavyData />  <!-- .server.vue component -->
</template>

When to Use Each Approach

ApproachUse Case
ssr: true + server componentsFull SSR with optimized islands
ssr: false (SPA)Admin dashboards, apps behind auth
Route-specific SSRMixed public/private pages

Migration Guide

From SPA to Hybrid

// nuxt.config.ts
export default defineNuxtConfig({
  // Step 1: Enable SSR globally
  ssr: true,

  // Step 2: Disable for existing SPA routes
  routeRules: {
    '/app/**': { ssr: false }
  }

  // Step 3: Add server components gradually
  // experimental: { componentIslands: true }
})

Quick Checklist

  • Server components require ssr: true
  • Don’t use .server.vue with ssr: false
  • Use route rules for selective SSR
  • Consider hybrid approach for mixed needs
  • Rename .server.vue files if not using SSR
  • Use ClientOnly for client-specific components