The Web Platform Behind Dropbox’s Evolution

In late 2021, Dropbox began quietly testing an internal alpha of its core web file browser. The milestone wasn’t the interface itself—it was the underlying architecture. That browser was now a Single Page Application (SPA), a shift that might be unremarkable for most sites but represented a fundamental change for Dropbox.com, a sprawling property backed by hundreds of services and dozens of feature teams.

The move wasn’t just about adopting a new front-end pattern. It required building an entirely new platform, called Edison, to support it. Edison is a complete rewrite of Dropbox’s core web serving systems, retiring roughly 13 years of accumulated technical debt. The goal: a framework that supports sub-second developer iteration, isomorphic JavaScript that runs on both client and server, and a unified SPA across the entire web surface—without forcing every team into a painful migration.

From Desktop App to Web Platform

Dropbox launched in 2008 as a desktop-first product, with the website serving mostly as a delivery and marketing channel. Engineering focus was on sync, networking, and storage—not the browser. Over time, the web presence grew from a simple brochure to an account manager, file viewer, and eventually a platform for advanced features like PDF editing and video collaboration.

Today, the web is central to every Dropbox product. As the company pushes into new workflows and cloud-only data, the web has become the primary battleground for user value. The shift to Edison reflects a broader cultural change: Dropbox now treats the web as a first-class engineering surface, not an afterthought.

Legacy Architecture and Its Limits

The previous stack mirrored the broader history of web development. Early code relied on Pyxl, a Python-with-inline-HTML engine, alongside CoffeeScript before a migration to TypeScript. jQuery came and went, React was adopted, and the team built custom infrastructure to address specific business needs—most notably a custom webserver called DWS.

DWS worked well for years, enabling independent feature development through a pagelet architecture. Each pagelet bundled backend controller code and frontend view code, executing in parallel and streaming data into the browser while the HTTP connection stayed open. A route was simply a collection of pagelets.

This design had clear benefits:

  • Complex pages could be broken into manageable vertical slices.
  • Each team owned its product code with clear separation.
  • Independent rendering meant one team couldn’t block another.
  • Parallel backend requests made early data retrieval possible, so JS execution often found its data already available.

But the architecture hit two major walls as ambitions grew.

The Pagelet Bottleneck

The first problem: data-fetching instructions lived in Python controllers while the data itself was consumed by JavaScript in the browser. Keeping those two layers in sync was manual and error-prone. It was easy to over-fetch data or leave stale fetches behind as the front end evolved. Static verification was nearly impossible.

More critically, crossing pagelet boundaries was extremely difficult. Building any feature that required two pagelets to interact meant designing a mutual messaging API with the owning team—a process that effectively blocked holistic application development and made a SPA unattainable.

Commingled Server and Client Layers

The second problem stemmed from DWS’s origin inside HTML-in-Python. The server and JavaScript client were tightly coupled, making modular execution impossible. An engineer working on a small JS or CSS change typically had to run the entire webserver stack to see any result.

That wasn’t just an inconvenience—it was a scale problem. A typical project might start a dev server in 10-20 seconds, but Dropbox’s web property depended on roughly 100 backend services, all compiled and launched inside a virtualized environment called devbox. Startup times ranged from 20 minutes to, in worse cases, 40. An experienced frontend engineer joining the company could watch their iteration cycle stretch from seconds to half an hour or more.

Tools like Storybook offered partial relief for isolated modules, but they were patches, not solutions. Engineers shouldn’t need to reverse-engineer how to run each piece of code every time they needed to test it. Dropbox needed a general, universal answer.

What Edison Had to Get Right

Engineering teams rarely have the luxury of a clean rewrite, and Dropbox was no exception when building its web client architecture. The system that was ultimately developed—Edison—needed to meet a set of strict non-functional requirements to be viable. A full rewrite of nearly two million lines of TypeScript was a non-starter, and not just for technical reasons. Individual teams had their own back ends and pagelet implementations; asking them to re-architect that code would cause delays and political fallout severe enough to sink the project before it launched.

Performance was equally non-negotiable. The prior system, DWS, had established clear optimization lines. Edison had to match them while ensuring that parallel products couldn’t interfere with one another and that data fetches consistently happened well before the JavaScript initialization kicked off. The target that emerged by 2020 was a serverless client architecture paired with a Node-based rendering server—an isomorphic JavaScript stack tightly coupled to Dropbox’s existing services and code structure.

The Structure of Edison

Edison is composed of three major components that divide responsibilities between routing, rendering, and client-side execution.

  1. Edison Server is written in Go and accepts direct web traffic via the corporate Envoy proxy layer. It delegates server-side rendering (SSR) to Streaming Reactserver, performs data fetches via Courier (Dropbox’s gRPC framework), and handles all ahead-of-time fetching, communicating with Edison Client in the browser.
  2. Streaming Reactserver is a Go-wrapped Node service tasked specifically with performing React tree renders. Crucially, it can pass messages back to Edison Server asynchronously during the render process.
  3. Edison Client is the browser-based runtime: the main entry point that interfaces with Edison Server for ahead-of-time data fetch guarantees, handles data exchange directly with Courier services for late fetches, and implements a single React app for the entire page.

Running serverless is a core design property of Edison. In principle, Edison Client and product code can be served from a static CDN without any server component. Production doesn’t work that way, but the capability is an enabling feature. That raises a reasonable question: if it can run without a server, why have Edison Server at all? The answer is that Edison Server acts as a runtime accelerator. It pre-processes the application tree and data requirements to meet performance targets that a purely client-side architecture could not.

Acceleration Through Application Analysis

To understand the value of server acceleration, consider a page that renders a file listing with an overlaid PDF preview. In the old model without early data fetches, a client would naively respond to a request for /browse with a JavaScript entry point bundle. Once loaded, the browse app requests data for the user. Then, with that data in hand, the browse app determines it needs the preview JS app. Finally, when that second bundle loads, the page can render fully.

A diagram showing an example of a naive cascade for a pure-client JS application

An example of a naive cascade for a pure-client JS application

These linear dependency chains escalate quickly; a real production application can easily have hundreds of such interacting modules. Edison Server short-circuits this cascade by pre-analyzing the whole application tree to anticipate the data requests each route will need. The result is that the required resources become available in parallel rather than sequentially.

The same sequence, with modules and data preloaded

This kind of acceleration comes down to the asynchronous communication between Edison Server and Streaming Reactserver during a server-side render. When a request arrives, the sequence breaks down like this:

  1. Edison resolves the route to a JS entry point module, packages up all the data required to render that entry point, and sends it to Streaming Reactserver.
  2. Streaming Reactserver begins the server-side render. As the code path executes, it encounters data fetch calls, specifically to Edison.prefetch.
  3. When those calls are hit, Streaming Reactserver sends an asynchronous message to Edison Server, which immediately kicks off the data fetch while the React render continues.
  4. When that data fetch completes, Edison Server streams the results into the response HTML, whether or not the React render has finished, ensuring the data is ready exactly when the application needs it.

The performance characteristics of DWS are preserved, but the architectural penalty is gone. Data fetch requests are now co-located with the code that depends on them, and all application logic exists in a single system layer.

Migrating Without the Pain

Edison was designed to continue a phased migration that had moved page APIs from Python and Pyxl over to JS. Teams that had been keeping up held two pieces: a Python pagelet executor for data loads and initialization data, and JS application code that consumed that data. Moving to Edison meant swapping the executor for a data servicer (in Python, Go, or any supported language) that handled loads over gRPC and wrote a JS entry point that implemented Edison.prefetch calls to the servicer.

For most teams, this was the work of refactoring a single Python file—repackaging with the Servicer API instead of the Pagelet API—and adding a new JS entry point module. The rest of the front-end core and back-end core code could be shared without duplication. Teams could do the work incrementally, with the Edison version gated to internal traffic, and expect reasonable feature parity immediately.

Those incremental refactors demanded time and capital leading up to launch, but they paid off. By the time Edison was ready, major web services could run simultaneously on DWS and Edison with the same JS code, making gradual rollouts a low-risk operation rather than a big-bang switchover.

What Edison Solved—and Where It Left Off

The foundational wins from the Edison architecture are concrete. Product code now lives entirely in the TypeScript layer, ending the commingled application layers of the prior system. Early data fetch and acceleration are preserved through asynchronous gRPC calls initiated during the server-side render. The two sources of truth for data fetches collapsed into one, which made code easier to read and maintain.

Individual product modules—the old pagelets—retained ownership of their back end data providers while executing their JS code as soon as the initialization data arrived. Because the whole page is a single coherent React tree, engineers can easily write functionality that crosses what used to be hard pagelet boundaries. Routes that had been fully ported to React could run on both DWS and Edison simultaneously, which de-risked the final migration step.

Yet a major developer productivity gap remained. Running any JS with the old architecture meant running the full stack of more than 100 services. Edison had not yet reduced that burden. Solving that problem—giving engineers a setup where executing code doesn’t require operating the entire serving ecosystem—became the next major goal, and a key motivation for the progress that followed in the full Edison rollout.

What a unified React tree unlocks

Consolidating the Dropbox.com surface onto Edison gave the team a single, coherent React tree to work in—a return to the SPA-style architecture that had guided earlier migrations. It also cleanedly separated client from server: the client no longer needed to be served from the webserver, which in turn simplified the developer workflow.

A Single Page Application isn’t the right answer for every site, and it’s not necessarily the end state of our architecture. For mostly-static properties, a thinner client can address the same problems more simply. But Dropbox on the web functions as a full graphical file manager—uploading, moving, and manipulating files is the core activity. Decoupling user actions and page state from navigation around the surface is essential for that kind of product.

The SPA structure delivers concrete benefits here:

  • Navigating the file tree becomes intuitive, so actions like dragging a file into the sidebar work across what used to be separate React applications.
  • Visual transitions between surfaces—such as folder navigations—show users what changed and reduce cognitive load.
  • Navigation is powered by a single API call rather than a full page load, improving performance.

Edison Localmode: separating client development from the server

Once the client no longer depended on the webserver, several new capabilities opened up: bundling sources and deploying to a CDN, running the app in Electron through a unified cross-platform pipeline, and serving the entire web client from an engineer’s laptop. The third option was the one that solved the developer productivity problem this work set out to fix.

The goal of Edison Localmode is straightforward: web client developers should not need to run anything but the web client. Engineers iterating on JS and CSS should be able to work against a pure client codebase that talks to the rest of Dropbox through APIs, without repeatedly touching the webserver or other back end services.

Edison Localmode is opt-in. It serves all static assets—JS and CSS—directly from an engineer’s development laptop. An engineer loads a page normally from a Dropbox webserver (either a dev server they’ve started or the staging environment), boots a lightweight local Node-based asset server, and opts into Localmode. From that point until they opt out, all static assets come from the local machine.

Once active, the local server watches the filesystem and re-transpiles code on the fly, patching changes directly into the running page. Modifications appear instantly, with no manual step required.

Before and after

The change is small to state but transformative in practice.

Before:

  1. An engineer modifies and saves a source file.
  2. They manually issue a command to reload devbox, which syncs changed files, rebuilds, and restarts services.
  3. After 15–30 seconds, they switch back to the browser and hit refresh.
  4. If the code sits deep in a flow—say, the third stage of an interactive form—they must manually reconstruct that state after every refresh.
  5. Once reloaded, they check whether the code works.
  6. Repeat until the feature is complete.

After:

  • An engineer modifies and saves a source file.
  • The code is transpiled and running in the page, with all state intact, before they’ve even switched back to the browser.

The raw time savings add up. Reloading every 15 minutes at the conservative end of devbox speeds saves roughly one minute per hour; at six hours a day, that’s around four working days a year. Less quantifiably, a 30-second delay invites an engineer to check Slack, breaking flow and costing far more time than the delay itself. Instant feedback keeps engineers in flow and speeds up iteration.

Front end development on devbox was a notoriously frustrating experience. Edison Localmode makes previously tedious work fast again.

Looking ahead

Edison is the product of a broader shift at Dropbox. As the web grew in importance, the engineering team diversified from mostly back end engineers to include a strong full-stack web cohort; Edison wouldn’t have been possible without that culture change.

Developing Edison also exposed implicit assumptions baked into the older DWS system. Understanding and isolating those constraints required incremental adjustments to APIs and the code that used them—work that clarified what future alignment with open source would look like and what it would take to get there. Reducing reliance on bespoke tools and moving toward open-source standards remains an ongoing goal.

In the meantime, Edison is a major accelerator for product development. Features that would have been lengthy projects under DWS are now straightforward, and development work that was punctuated by interruptions has become continuous. That frees the team to think more boldly about what the Dropbox.com web experience should be.