CoffeeScript at Dropbox: A Hackweek Rewrite

During a July Hackweek, we rewrote Dropbox's entire browser-side codebase from JavaScript to CoffeeScript—roughly 23,000 lines of code. After the week was over and the change was fully launched to users, the results have been positive enough that all new frontend code at Dropbox is now written in CoffeeScript.

Before committing to the rewrite, we weighed the two most common objections to CoffeeScript and found neither held up in practice.

Concern: recompilation overhead. Iterative development with CoffeeScript requires each change to be compiled to JavaScript before it can be tested. We solved this by instrumenting our development server: on every page reload, it compares modification times between .coffee files and their compiled .js counterparts, recompiling only what changed. Compilation is fast enough that the process is imperceptible—no coffee --watch, no new workflow, no background processes. Just write, reload, repeat.

Concern: debugging compiled JavaScript. CoffeeScript is designed to map cleanly to JavaScript semantics, which keeps debugging straightforward. We converted and debugged the full codebase in one week without significant issues, then tested carefully and rolled out gradually.

Why JavaScript's Flaws Matter

The most misleading argument we hear is that CoffeeScript is merely a syntactic preference—if you like Python or Ruby, you'll like CoffeeScript. This ignores history. JavaScript was born in September 1995 as LiveScript, created in just ten days under management pressure to produce "Java's dumb kid brother." It launched with Netscape Navigator 2.0 and was renamed to JavaScript months later for marketing reasons. Microsoft shipped its own version called JScript in IE 3.0, and the ensuing standardization process produced ECMAScript—a name even Brendan Eich has called "an unwanted trade name that sounds like a skin disease."

Despite its rushed origins, JavaScript got many fundamentals right: first-class functions, prototypes, dynamic typing, object literals, and closures. But it also accumulated genuine design flaws: confusingly classical syntax obscuring prototypal inheritance, the footgun of an omitted var creating a global, automatic type coercion with == versus ===, automatic semicolon insertion pitfalls, and the array-like-but-not-quite arguments object. Because the language was already entrenched in competing browsers and frozen by an international standards body, fixing these problems takes years of coordination. CoffeeScript sidesteps that slow evolution by providing modern constructs now—default arguments, splats, multiline strings, and iteration improvements—without waiting for browser vendors to agree.

To be clear, we are not unbiased: Python is Dropbox's primary language and we love it. But even setting significant whitespace aside, CoffeeScript solves many of JavaScript's syntactic problems.

Reading Versus Symbols

One argument against CoffeeScript suggests that because humans process images faster than words, verbose JavaScript may actually be more quickly comprehended than terse CoffeeScript. While the premise about image processing has merit, the conclusion doesn't follow for several reasons:

  • CoffeeScript mostly doesn't replace symbols with words—it drops symbols entirely. Removing frequent noise like commas, semicolons, braces, and parentheses makes code easier to parse, not harder.
  • CoffeeScript introduces new notation, such as (a,b,c) -> ... instead of function (a,b,c) {...}. This is shorter to type and, like mathematical notation, can improve comprehension.
  • Even where CoffeeScript does use a word for a symbol—or versus ||—the symbolic form isn't inherently more visual. The character sequence || isn't an icon for logical disjunction; it's a stand-in for the word or. Replacing the stand-in with the real word likely adds little cognitive overhead and may even reduce it.

Line and Token Reduction

The rewrite removed over 5,000 lines of code, a 21% reduction. Some of these were mechanical removals—boilerplate function wrappers and braces—but the effect is real: more code fits on a single screen. Token count provides a better first-order measure of complexity reduction, and those statistics strongly favor CoffeeScript.

 JavaScriptCoffeeScript
Lines of code2343718417
Tokens7533466058
Characters86561365993

In production, we compile and concatenate all CoffeeScript into one JavaScript file, minify it, and serve it with gzip compression. The compressed bundle size is essentially unchanged, so user-visible performance is identical to before.

Conversion Strategy

Rewriting 23,000 lines in a week required more than manual effort. We used js2coffee, a JavaScript-to-CoffeeScript compiler, to handle repetitive conversions. Each file was first run through the compiler, then hand-edited to improve style and idiomatic usage.

The compiler has its limits. It cannot, for example, convert a three-clause JavaScript for loop into a CoffeeScript for/in, so we manually replaced those with simpler constructs. We also swapped string concatenation for interpolation where appropriate.

Testing relied on three complementary approaches:

  1. Jasmine for unit tests.
  2. A custom fuzz tester built with Selenium that performs a random walk across the site looking for exceptions.
  3. Extensive manual testing.

What's Next

Since the launch, we've written several thousand more lines of CoffeeScript. Two areas we're watching: browser support for CoffeeScript source maps, which would let us trace JavaScript exceptions directly to the original source, and native CoffeeScript support in browsers to eliminate the compilation step during development.