A guided explainer

Reach for what you already ship

The Google Closure Library is already inside every ClojureScript build. Here is what that means — and how to know when to use it instead of an npm package, the standard library, or the browser.

You are three days into a ClojureScript project. A search box is firing a request on every keystroke, and you want it to wait until the typing stops — to debounce. Your fingers already know the answer, npm install lodash.debounce, and they are halfway through typing it.

Wait. You almost certainly already have debounce. It is in your build right now — written, tested, shipped by Google — and you didn’t add it. This page is about the large, useful library that arrives with ClojureScript whether you notice it or not, why it is so easy to miss, and the small guide we built so that you (and the AI agent writing alongside you) stop reinstalling things you already own.

What is already in the box

One fact about how ClojureScript is built explains the whole thing. ClojureScript does not compile to JavaScript on its own; it compiles through Google’s Closure Compiler, the optimizer that shrinks and checks the final code. And bundled with that compiler is its companion, the Google Closure Library Everything in it lives under the goog. name — goog.functions, goog.crypt, goog.i18n, and hundreds more. That is why you’ll see “goog” throughout this page; it just means “from the Closure Library.” — a batteries-included JavaScript toolkit Google has maintained and shipped in production (Gmail, Maps, Docs) for well over a decade.

It is not an add-on. cljs.core — the standard library you use in every file — is itself built on top of it. Every ClojureScript build already contains it, and any namespace can reach it with a plain require. The version is pinned to the exact one the ClojureScript compiler uses, so what you ship and what the docs describe are always the same library — no drift, no separate install to keep in sync. The Closure Library is not something you install. It is already in the box you are holding.

So why does nobody reach for it?

Two reasons, and neither is that the library is missing things. The first is size: it is enormous. Read straight from the compiler, it holds 68,083 named pieces — functions, classes, constants. The second is that its documentation is written for JavaScript developers and organized strictly by name, with no view of what matters to someone writing a modern ClojureScript app.

Faced with a wall that size, the path of least resistance is the npm package whose name you already know. So the library quietly has the function you need — debounce, a hash, a color conversion, a 64-bit integer — and you install a dependency for it anyway. The problem was never absence. It was discoverability, and judgment: knowing the thing exists, and knowing when it is the right call.

First we made it findable

The obvious fix is a good map, so that is what we built first: a tool that reads the entire library straight out of the compiler and writes it back out as documentation tuned for ClojureScript — every symbol with the exact call form you’d type.

Under the hood: how the map gets made

Three steps, fully automatic. Extract: ask the Closure Compiler itself for every symbol it knows, so nothing is guessed — the source of truth is the compiler, not a human. Enrich: work out, for each symbol, the precise ClojureScript form to call it and which symbols inherit from which. Render: write it all out as plain pages. The result is about 2,196 pages, one per symbol, plus a catalog that lists them all.

It is faithful and it is complete. But complete is not the same as actionable. A machine can only organize the catalog the one way it can derive automatically: by name — 314 sections, one per namespace, alphabetical. Which is useless at the exact moment you need it, because you don’t know the name yet. You know the capability: “debounce.” Watch what each version gives back when that is all you have:

Search the catalog for “debounce” and you land on a heading:

## goog.functions

No description — a list of function names has no prose to show. Nothing tells you this namespace is where debounce lives, or that you want it over the heavyweight class one section away. A list of every street is not directions.

The piece a machine can’t write

A reference answers “what is goog.crypt.Sha256?” That is a fine question, but it is not the one you have. Yours is: “I need to hash a string — what do I reach for, and should I even use the Closure Library here?”

That second question is judgment, and no amount of reading the library produces it automatically. Sometimes the Closure Library is the right answer. Sometimes the standard library already does it better and reaching for goog. would be a step backward. Sometimes the browser itself has grown the feature since the library was written. Telling those apart is a human call — so we made it, by hand, one capability at a time, and wrote it down where the tools (and the agents) can read it.

Four answers, not one

Each entry in the guide starts with a need, names the npm package you might otherwise install, points at the Closure symbol — and gives one of four verdicts. The verdict is the judgment; it is the part that matters.

CL  Use the Closure Library. Core doesn’t have this, and the library does it well. Debouncing is the clean example: reach for goog.functions.debounce and skip lodash.debounce entirely.

core  Use the standard library instead. Here cljs.core already wins, and reaching for goog. would be the wrong move. Need a UUID? It’s cljs.core/random-uuid — not an npm package, and not the Closure Library, which has no real UUID at all.

native-first  The browser already has it. Try the built-in first; keep the library for the harder edges. Formatting a date for a locale is Intl.DateTimeFormat in any modern browser — lean on the Closure Library only when you need its pattern language.

gap  Nobody has it cleanly — here’s the honest workaround. An automatic retry-with-backoff, say: the library gives you the backoff schedule (goog.math.ExponentialBackoff), but you still drive the retry loop yourself. The guide says so plainly rather than overselling.

That is the whole idea, repeated across every common need. The full set is the Field Guide — a table you can search and filter by verdict.

Why you can trust it

A hand-written guide has a failure mode a generated one doesn’t: it can quietly go wrong. A symbol gets renamed in a library update and the guide keeps pointing at a name that no longer exists — a confident, dead reference, which is worse than no guide at all.

So the guide doesn’t rely on us having been careful. Every Closure symbol it names is checked against the real library on every single build, and if even one has gone missing, the build stops and says which. The curation is human; the proof that it’s still true is automatic. How we keep it honest walks through exactly how, and why that matters whenever you build a guide of your own.

How to use it

The curated index rides at the top of the file an AI agent reads first when it works in your codebase, so the agent gets the same four-way judgment you do — reach for the library, or core, or the browser, or roll it yourself. The Field Guide is the same thing for human eyes.

But you don’t need either open to get the benefit. The habit is the point. Next time your fingers start typing npm install for something small and standard — a hash, a debounce, a color tweak, a date format — pause for one second and ask the question this whole project is built around:

Is this already in the box?


Grounded in the goog-docs project — figures (68,083 symbols, ~2,196 pages, 314 catalog sections) are read from the live model, not estimated.  ·  The Field Guide  ·  Keeping it honest