---
title: "Dynamic Rendering (Deprecated)"
description: "Dynamic rendering serves pre-rendered HTML to crawlers while users see JavaScript. Google no longer recommends this. use SSR or SSG instead."
canonical_url: "https://nuxtseo.com/learn-seo/vue/spa/dynamic-rendering"
last_updated: "2026-01-29"
---

<key-takeaways>

- **Deprecated Strategy**: Google explicitly advises against Dynamic Rendering for new projects in 2026
- **Risk of Cloaking**: Serving different content to bots vs. humans can trigger penalties if not synchronized
- **Use SSR/SSG**: Modern frameworks (Nuxt, Vite SSR) solve the same problems without the complexity or risk

</key-takeaways>

Dynamic rendering detects crawler requests and serves them pre-rendered HTML, while users receive client-side rendered content.

<warning title="Avoid for New Projects">

As of 2026, Google explicitly treats Dynamic Rendering as a "workaround" and **no longer recommends it**. It adds infrastructure complexity, increases error rates, and offers no performance benefit to real users (INP).

Use **Server-Side Rendering (SSR)** or **Static Site Generation (SSG)** instead.

</warning>

## Why Google Deprecated It

Google [positions dynamic rendering](https://developers.google.com/search/docs/crawling-indexing/javascript/dynamic-rendering) as error-prone, increasing server load and maintenance burden. Serving different content to crawlers versus users risks "cloaking" violations if implementations diverge.

**The Core Issues:**

1. **Maintenance Nightmare**: You are maintaining two websites. One for bots, one for humans.
2. **Cloaking Risks**: If your "bot version" shows content that isn't in the "user version" (or vice versa), Google may penalize your site.
3. **Fragile Detection**: User-agent sniffing is unreliable. New bots, AI agents, and crawler updates break your detection logic constantly.
4. **No User Benefit**: Real users still get the slow Client-Side Rendered app, suffering from poor **INP** (Interaction to Next Paint).

## Migration Path: Moving to SSR

If you are currently using Dynamic Rendering or a legacy render service, plan your migration to Server-Side Rendering (SSR).

**Step-by-Step Migration:**

1. **Audit Dependencies**: Identify Vue libraries that are client-only (access `window` or `document` on import).
2. **Adopt a Framework**:

  - **Best**: Move to [Nuxt](https://nuxt.com). It handles SSR, hydration, and data fetching by default.
  - **Alternative**: Use `vite-ssg` if your site is static.
  - **Hard**: Implement custom SSR with [Vite](https://vite.dev) (only for advanced teams).
3. **Wrap Client-Only Code**: Use `<ClientOnly>` components or `onMounted` hooks for parts of your app that strictly require the browser.
4. **Test Incrementally**: You don't have to switch overnight. Use Nginx or your edge router to send 10% of traffic to the new SSR app while keeping the rest on the old setup.
5. **Shutdown Dynamic Renderer**: Once your SSR app is stable, remove the middleware that detects bots. Treat bots and humans the same.

## Historical Context: How It Worked

*This section is for understanding legacy codebases only.*

Dynamic rendering relied on middleware to intercept requests.

<code-group>

```ts [Express (Legacy)]
import express from 'express'
import rendertron from 'rendertron-middleware'

const app = express()

// ❌ The old way: Sniffing user agents
app.use(rendertron.makeMiddleware({
  proxyUrl: 'https://render-tron.appspot.com/render',
  userAgentPattern: /googlebot|bingbot|slurp|duckduckbot/i
}))
```

</code-group>

This required a headless browser service (like Puppeteer or Rendertron) to spin up, load the page, wait for network idle, and serialize the HTML. This was slow, expensive, and flaky.

## Cloaking Risk

Serving crawlers different content than users violates [Google's webmaster guidelines](https://developers.google.com/search/docs/crawling-indexing/javascript/dynamic-rendering) if the versions diverge. JavaScript errors in user version while crawler gets perfect HTML triggers manual penalties.

Keep rendered output identical:

- Test both versions regularly
- Monitor JavaScript errors in production
- Use same data sources for both renders
- Log differences and alert on mismatches

Safer to fix SSR hydration issues than maintain two code paths.

## Using Nuxt?

Nuxt handles server-side rendering automatically. No need for dynamic rendering workarounds.

[Learn more about Nuxt SEO →](/learn-seo/nuxt/routes-and-rendering/rendering)
