Pinning Library Versions in CodePen External Resources for Reproducible Pens
Stop Pens from breaking when CDN libraries update. Pin exact versions in CodePen External Resources, verify loads, and avoid common pitfalls with UMD builds and load order.
09 Jul 2025, 15:07 UTC

If a Pen works today and breaks tomorrow with no code changes, the likely culprit is an unpinned CDN URL in Settings → CSS/JS → External Resources. When you paste a link like https://cdn.jsdelivr.net/npm/lodash@latest/lodash.min.js, CodePen fetches whatever the CDN currently serves under that alias. A major version bump can remove globals or change behavior. The fix is simple: use a CDN URL that contains an exact version number, such as lodash@4.17.21. This article explains how CodePen loads those resources, shows a pinned React and Bootstrap configuration, and covers the limits that still apply.
How External Resources load in a Pen
CodePen does not bundle, transpile, or rewrite the files you add through the External Resources panel. When the preview iframe renders, CodePen injects a <link rel="stylesheet"> tag for each CSS URL and a <script src=""> tag for each JavaScript URL. The browser then fetches those files directly from the CDN. Because the editor does not transform them, the URL you paste is the exact URL the browser requests.
Every External Resource must use HTTPS. CodePen blocks plain HTTP URLs, and a CDN that redirects to HTTP can trigger mixed-content errors—when a secure page requests an insecure file—in the browser console, causing the resource to fail silently in the preview.
Worked example: pinning React and Bootstrap
Suppose you want a React 18 Pen with Bootstrap 5 styling. Open the Pen, click Settings → CSS/JS, and scroll to the External Resources section. Add the following URLs:
- CSS:
https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css - JS:
https://cdn.jsdelivr.net/npm/react@18.2.0/umd/react.production.min.js - JS:
https://cdn.jsdelivr.net/npm/react-dom@18.2.0/umd/react-dom.production.min.js
Set the JavaScript preprocessor to Babel so JSX in the JS pane compiles before execution. The preview then requests those three exact files. In the browser console, React.version returns '18.2.0', confirming the pinned build loaded rather than a floating @latest alias.
Notice that the React URLs point to the umd/ directory. UMD (Universal Module Definition) builds attach globals such as React and ReactDOM to window, which is what an External Resource needs. If you accidentally paste an ESM-only URL—one that uses import/export syntax—the browser will load it as a classic script, fail to parse the module syntax, and leave window.React undefined.
Load order and preprocessor interaction
CodePen loads External Resources in the order you list them, after any preprocessed code from the HTML, CSS, and JS panes. The editor does not analyze dependencies. If you add Bootstrap's JavaScript before jQuery, Bootstrap will initialize before its required global exists and throw an error. List dependencies first: jQuery, then Bootstrap JS.
The same ordering rule applies to CSS. A custom stylesheet added as an External Resource loads after CodePen's own CSS reset and after any preprocessed CSS. If your external stylesheet relies on a variable or mixin defined in your Sass, it will not see it, because Sass compiles before the external file arrives.
Limits and common mistakes
No Subresource Integrity checks
CodePen does not verify SRI hashes for External Resources. SRI (Subresource Integrity) is a browser security feature that checks a fetched file against a cryptographic hash. If a CDN is compromised or serves unexpected bytes, the preview will execute them. For high-security demos, either host the file yourself through CodePen Asset Hosting (Pro) or add the integrity attribute manually in the HTML pane with a standard <script> tag rather than the External Resources UI.
Exports reference URLs, not bytes
When you export a Pen to a zip file or GitHub Gist, the External Resources are not inlined. The exported HTML contains the same CDN URLs. If the CDN later removes that version—some providers garbage-collect old releases—the exported Pen will break. For an offline archive, download the files and reference them locally.
Rate limits and availability
Public CDNs apply rate limits. A demo shown to a large audience can trigger HTTP 429 responses, making the Pen appear broken for some viewers. Asset Hosting or a private CDN avoids this, but only if you control the infrastructure.
Relative @import in external CSS
If an external stylesheet contains @import url("fonts.css"); with a relative path, the browser resolves it against the CDN's directory structure. Some CDNs do not serve sibling files correctly for arbitrary paths. Prefer flat, self-contained CSS files or absolute import URLs.
Version drift with aliases
Aliases such as @latest, @next, or a bare major version like react@18 can mutate over time. A bare major version is safer than @latest but still allows minor and patch updates. For true reproducibility, pin the full semantic version: react@18.2.0.
Verifying the result
After saving the External Resources, open the Pen's preview in a new tab, open your browser's developer tools, and check the Network tab. Each pinned URL should return 200 OK. To confirm the version, type React.version in the console; it should match the number in your URL.
For team workflows, paste the exact CDN URLs into the Pen description or a shared template. If you have CodePen Pro, create a Pen Template with the pinned resources already configured; every new Pen forked from that template inherits the same list without manual re-entry.
When pinning is not enough
Pinning solves the most common reproducibility problem, but it does not make a Pen self-contained. The preview still depends on the CDN's uptime, the browser's cache state, and the absence of network filtering. If your demo must run in an air-gapped environment or during a conference with unreliable Wi-Fi, download the libraries and use Asset Hosting or inline them in the HTML pane.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.