SSR hydration mismatch (all class names differ between server and client) introduced in 6.3.12 with webpack + nodeExternals
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 bundlestyled-components— itrequire()s it at runtime fromnode_modules, loadingdist/styled-components.cjs.js. - Client bundle: webpack with
target: 'web'. webpack resolves thebrowserfield in styled-components'package.jsonand bundlesdist/styled-components.browser.cjs.js. - Server-side rendering uses
ServerStyleSheet+collectStyles/getStyleTags(). babel-plugin-styled-componentsconfigured 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
- Use webpack with
webpack-node-externalsfor SSR (server does not bundle styled-components). - Use webpack
target: 'web'for the client bundle (webpack picks up thebrowserfield →styled-components.browser.cjs.js). - Use
ServerStyleSheet/collectStyles/getStyleTags()for SSR. - Upgrade from
[email protected]to6.3.12or later. - 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