diff --git a/static/warnings.js b/static/warnings.js
new file mode 100644
index 000000000..799f55cad
--- /dev/null
+++ b/static/warnings.js
@@ -0,0 +1,125 @@
+(function() {
+    function load(key, def = null) {
+        const value = window.localStorage.getItem(key);
+        if (value) {
+            try {
+                return JSON.parse(value);
+            } catch (ex) {
+                console.error(`Failed loading ${key} from local storage`, ex);
+                return def;
+            }
+        } else {
+            return def;
+        }
+    }
+
+    function store(key, value) {
+        window.localStorage.setItem(key, JSON.stringify(value));
+    }
+
+    function create(tagName, attrs = {}, children = [], listeners = {}) {
+        const el = document.createElement(tagName);
+        for (const key of Object.keys(attrs)) {
+            if (typeof attrs[key] === "object") {
+                for (const subkey of Object.keys(attrs[key])) {
+                    el[key].setProperty(subkey, attrs[key][subkey]);
+                }
+            } else {
+                el.setAttribute(key, attrs[key]);
+            }
+        }
+        el.append(...children);
+        for (const key of Object.keys(listeners)) {
+            el.addEventListener(key, listeners[key]);
+        }
+        return el;
+    }
+
+
+    if (!load("docs-rs-warnings-enabled", false)) {
+        return;
+    }
+
+    const parentEl = document.getElementById("warnings-menu-parent");
+    parentEl.removeAttribute("hidden");
+
+    const current = JSON.parse(document.getElementById("crate-metadata")?.innerText || null);
+
+    const menuEl = document.getElementById("warnings-menu");
+
+    const followed = load("docs-rs-warnings-followed", []);
+
+    function update() {
+        const children = [];
+
+        if (followed.length > 0) {
+            children.push(
+                create("div", { class: "pure-g" }, [
+                    create("div", { class: "pure-u-1" }, [
+                        create("ul", { class: "pure-menu-list", style: { width: "100%" } }, [
+                            create("li", { class: "pure-menu-heading" }, [
+                                create("b", {}, ["Followed crates"]),
+                            ]),
+                            ...followed.map(name => (
+                                create("li", { class: "pure-menu-item followed" }, [
+                                    create("a", { class: "pure-menu-link", href: `/${name}` }, [
+                                        name,
+                                    ]),
+                                    create(
+                                        "a",
+                                        { class: "pure-menu-link remove", href: "#" },
+                                        ["🗙"],
+                                        {
+                                            click: _ => {
+                                                const index = followed.indexOf(name);
+                                                followed.splice(index, 1);
+                                                store("docs-rs-warnings-followed", followed);
+                                                update();
+                                            },
+                                        },
+                                    ),
+                                ])
+                            )),
+                        ]),
+                    ]),
+                ]),
+            );
+        }
+
+        if (current && !followed.includes(current.name)) {
+            children.push(
+                create("div", { class: "pure-g" }, [
+                    create("div", { class: "pure-u-1" }, [
+                        create("ul", { class: "pure-menu-list", style: { width: "100%" } }, [
+                            create("li", { class: "pure-menu-item" }, [
+                                create("a", { class: "pure-menu-link", href: "#" }, [
+                                    "Follow ",
+                                    create("b", {}, [current.name]),
+                                ], {
+                                    click: () => {
+                                        const i = followed.findIndex(name => name > current.name);
+                                        if (i >= 0) {
+                                            followed.splice(i, 0, current.name);
+                                        } else {
+                                            followed.push(current.name);
+                                        }
+                                        store("docs-rs-warnings-followed", followed);
+                                        update();
+                                    },
+                                }),
+                            ]),
+                        ]),
+                    ]),
+                ]),
+            );
+        }
+
+        for (const child of children.slice(0, -1)) {
+            child.classList.add("menu-item-divided");
+        }
+
+        menuEl.replaceChildren(...children);
+    }
+
+    update();
+})();
diff --git a/templates/base.html b/templates/base.html
index 8085c8b39..b2ebad5ed 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -24,6 +24,7 @@
 
         <script defer type="text/javascript" nonce="{{ csp_nonce }}" src="/-/static/menu.js?{{ build_slug }}"></script>
         <script defer type="text/javascript" nonce="{{ csp_nonce }}" src="/-/static/index.js?{{ build_slug }}"></script>
+        <script defer type="text/javascript" nonce="{{ csp_nonce }}" src="/-/static/warnings.js?{{ build_slug }}"></script>
     </head>
 
     <body class="{% block body_classes %}{% endblock body_classes %}">
diff --git a/templates/header/topbar_end.html b/templates/header/topbar_end.html
index 92b7cfa4e..5723f5303 100644
--- a/templates/header/topbar_end.html
+++ b/templates/header/topbar_end.html
@@ -4,6 +4,8 @@
                 {# The global alert, if there is one #}
                 {% include "header/global_alert.html" -%}
 
+                {% include "header/warnings.html" -%}
+
                 <ul class="pure-menu-list">
                     {#
                     The Rust dropdown menu
diff --git a/templates/header/warnings.html b/templates/header/warnings.html
new file mode 100644
index 000000000..4c9d173a8
--- /dev/null
+++ b/templates/header/warnings.html
@@ -0,0 +1,7 @@
+<ul id="warnings-menu-parent" class="pure-menu-list" hidden>
+    <li class="pure-menu-item pure-menu-has-children">
+        <a href="#" class="pure-menu-link" aria-label="Warnings">Warnings <span id="warnings-count"></span></a>
+        <div id="warnings-menu" class="pure-menu-children">
+        </div>
+    </li>
+</ul>
diff --git a/templates/rustdoc/body.html b/templates/rustdoc/body.html
index 365be5086..f4382bfb7 100644
--- a/templates/rustdoc/body.html
+++ b/templates/rustdoc/body.html
@@ -1,5 +1,6 @@
 {%- set build_slug = slug::slugify(crate::BUILD_VERSION) -%}
 <script async src="/-/static/menu.js?{{ build_slug }}"></script>
 <script async src="/-/static/index.js?{{ build_slug }}"></script>
+<script async src="/-/static/warnings.js?{{ build_slug }}"></script>
 {# see comment in ../storage-change-detection.html for details #}
 <iframe src="/-/storage-change-detection.html" width="0" height="0" style="display: none"></iframe>
diff --git a/templates/style/_navbar.scss b/templates/style/_navbar.scss
index bd173f8ea..9a85e0170 100644
--- a/templates/style/_navbar.scss
+++ b/templates/style/_navbar.scss
@@ -362,6 +362,22 @@ div.nav-container {
             }
         }
     }
+
+    #warnings-menu {
+        .followed {
+            display: flex;
+            align-items: center;
+            :first-child {
+                flex: auto;
+            }
+        }
+        .remove {
+            padding: 0 .5em;
+            &:hover {
+                color: var(--color-error);
+            }
+        }
+    }
 }
 
 #nav-search, #nav-sort {