SSR hydration mismatch (all class names differ between server and client) introduced in 6.3.12 with webpack + nodeExternals

Author: zdilaCreated Apr 30, 2026Updated Jul 3, 2026

Description

After upgrading from 6.3.11 to 6.3.12 (and all later versions including 6.4.x), every single styled-component generates a different class name on the server vs. the client, causing React to report hydration mismatches for the entire component tree. Downgrading back to 6.3.11 resolves the issue.

Environment

Package Version
styled-components 6.3.12, 6.4.0, 6.4.1 (broken), 6.3.11 (works)
babel-plugin-styled-components 2.1.4
react 19.2.5
webpack 5.106.2
Node.js 24.14.0

Setup

  • Server bundle: webpack with target: 'node' + webpack-node-externals. The server does not bundle styled-components — it require()s it at runtime from node_modules, loading dist/styled-components.cjs.js.
  • Client bundle: webpack with target: 'web'. webpack resolves the browser field in styled-components' package.json and bundles dist/styled-components.browser.cjs.js.
  • Server-side rendering uses ServerStyleSheet + collectStyles / getStyleTags().
  • babel-plugin-styled-components configured with { ssr: true }.

Symptom

In development mode, React throws hydration errors for every styled-component in the tree. Example:

Hydration failed because the server rendered HTML didn't match the client.

<Animation__StyledAnimation>
  <div
+   className="Animation__StyledAnimation-sc-14yz3tx-0 gCnCGD"  ← client
-   className="Animation__StyledAnimation-sc-14yz3tx-0 fajRrh"  ← server
  >

The component ID (sc-14yz3tx-0) matches on both sides — confirming babel-plugin-styled-components is generating stable IDs. Only the dynamic class hash suffix differs, for every component including those with fully static CSS (no dynamic interpolations).

In production mode (process.env.NODE_ENV = 'production') the error is silently swallowed by React, but the mismatch still exists (potential flash of wrong styles).

Root cause hypothesis

The server loads dist/styled-components.cjs.js at runtime (via Node.js require), while webpack bundles dist/styled-components.browser.cjs.js for the client (via the browser field in package.json). These two files have different initialization code. Something changed between 6.3.11 and 6.3.12 in one or both of these files that causes the internal class name hashing to diverge between the two separate module instances.

Reproduction steps

  1. Use webpack with webpack-node-externals for SSR (server does not bundle styled-components).
  2. Use webpack target: 'web' for the client bundle (webpack picks up the browser field → styled-components.browser.cjs.js).
  3. Use ServerStyleSheet / collectStyles / getStyleTags() for SSR.
  4. Upgrade from [email protected] to 6.3.12 or later.
  5. Visit any SSR-rendered page in a browser with devtools open in development mode.

Expected: no hydration warnings, class names match between server and client.
Actual: hydration mismatch on every styled-component in the tree.

Workaround

Pin to [email protected].

Source: styled-components/styled-components