---
title: "Dynamic Rendering in Vue: Why to Avoid It"
description: "Google calls dynamic rendering a workaround, not a fix. See why, and how to migrate a Vue SPA to SSR instead."
canonical_url: "https://nuxtseo.com/learn-seo/vue/spa/dynamic-rendering"
last_updated: "2026-10-05"
---

::key-takeaways
- Google calls dynamic rendering a workaround, not a long-term solution, and recommends server-side rendering or static generation instead
- Google generally does not treat similar bot and user content as cloaking; materially misleading differences need a spam-policy review
- Separate crawler rendering adds infrastructure and maintenance. It does not improve the client app by itself
- Nuxt enables server rendering by default. Verify the replacement before removing an existing dynamic renderer
::

Dynamic rendering detects crawler requests and serves them pre-rendered HTML while real users get the client-rendered app. It was a common fix for SPA indexing problems before SSR tooling matured. Google's own guidance now calls it a workaround, not a long-term solution. Evaluate SSR or static generation before adding a separate crawler rendering path.

::warning
Google treats dynamic rendering as a workaround, not a recommended solution, and points to server-side rendering or static rendering instead. Google generally does not treat similar bot and human content as cloaking. A crawler-only renderer adds maintenance without improving the user-facing app by itself.
::

## Why Google Recommends Against It

Google [positions dynamic rendering](https://developers.google.com/search/docs/crawling-indexing/javascript/dynamic-rendering) as added complexity and maintenance burden: you're running two rendering paths for one site instead of one. The practical problems:

- You maintain separate response paths and need to compare their content
- User-agent detection can miss new clients or be spoofed; keep request routing under review
- Users still receive the client-rendered app. Its loading and interaction costs need separate fixes
- Content, cached output, and rendering dependencies need ongoing checks on both paths

## Is It Cloaking?

Not inherently. Google says it "generally doesn't consider dynamic rendering as cloaking" as long as both versions serve similar content. Google's cloaking policy concerns different content presented to manipulate search rankings and mislead users: Google's own example is a page about cats for users and a page about dogs for crawlers. The risk with dynamic rendering isn't a manual penalty for using it; it's the maintenance cost of keeping two code paths close enough that they never drift into that territory.

## Migrating to SSR

If you're running dynamic rendering or a legacy render service, here's the path off it:

1. **Audit dependencies.** Find Vue libraries that touch `window` or `document` on import; they can fail when executed on the server.
2. **Adopt a framework.** [Nuxt](https://nuxt.com) supplies SSR, hydration integration, and data-fetching APIs. Verify your page data and state transfer. `vite-ssg` works if your site is fully static. Custom SSR with [Vite](https://vite.dev) leaves the request and rendering pipeline in your app.
3. **Wrap client-only code.** Use `onMounted()`{lang="ts"} for browser-only effects. Framework-provided `<ClientOnly>`{lang="html"} components are another option. Avoid top-level imports of browser-dependent libraries in the server bundle.
4. **Roll out incrementally.** Test representative routes in a preview deployment. If your infrastructure supports staged traffic, compare content and errors before completing the move.
5. **Remove the dynamic renderer.** Once the replacement serves equivalent public content and correct metadata, remove obsolete crawler-routing middleware.

## How Dynamic Rendering Worked

Legacy implementations matched crawler user agents and forwarded requests to a headless rendering service. The service loaded scripts, waited for configured readiness, and serialized HTML. That required a reachable renderer, cache management, and checks that crawler and user content remained similar.

[Rendertron](https://github.com/GoogleChrome/rendertron) is archived. Do not copy an old public proxy endpoint into a new deployment. Follow the migration checks above.

Nuxt renders on the server by default. A working server-rendered or statically generated replacement can remove the separate crawler response path. Learn more about [rendering modes in Nuxt](/learn-seo/nuxt/routes-and-rendering/rendering).

## Checklist

::checklist{#vue-dynamic-rendering}
- Dynamic rendering, if present, has a migration plan toward SSR or SSG
- Identify browser-dependent imports and move browser-only work out of server execution
- Bot and human responses are verified to serve equivalent content while both paths still run
- Remove obsolete crawler middleware after verifying the replacement output
::

## Sitemap

See the full [sitemap](/sitemap.md) for all pages.
