diff --git a/modules/angular2/docs/web_workers/web_workers.md b/modules/angular2/docs/web_workers/web_workers.md
new file mode 100644
index 0000000000..e859fc6932
--- /dev/null
+++ b/modules/angular2/docs/web_workers/web_workers.md
@@ -0,0 +1,476 @@
+# WebWorkers in Angular 2: Documentation
+
+Angular 2 includes native support for writing applications which live in a
+WebWorker. This document describes how to write applications that take advantage
+of this feature.
+It also provides a detailed description of the underlying messaging
+infrastructure that angular uses to communicate between the main process and the
+worker. This infrastructure can be modified by an application developer to
+enable driving an angular 2 application from an iFrame, different window / tab,
+server, etc..
+
+## Introduction
+WebWorker support in Angular2 is designed to make it easy to leverage parallelization in your web application.
+When you choose to run your application in a WebWorker angular runs both your application's logic and the
+majority of the core angular framework in a WebWorker.
+By offloading as much code as possible to the WebWorker we keep the UI thread
+free to handle events, manipulate the DOM, and run animations. This provides a
+better framerate and UX for applications.
+
+## Bootstrapping a WebWorker Application
+Bootstrapping a WebWorker application is not much different than bootstrapping a normal application.
+The primary difference is that you don't pass your root component directly to ```bootstrap```.
+Instead you pass the name of a background script that calls ```bootstrapWebWorker``` with your root component.
+
+### Example
+To bootstrap Hello World in a WebWorker we do the following in TypeScript
+```HTML
+
+
+
+
+
+
+
+
+
+
+
+```
+```TypeScript
+// index.js
+import {bootstrap} from "angular2/web_worker/ui";
+bootstrap(loader.js);
+```
+```JavaScript
+// loader.js
+importScripts("https://github.jspm.io/jmcriffey/bower-traceur-runtime@0.0.87/traceur-runtime.js", "https://jspm.io/system@0.16.js", "angular2/web_worker/worker.js");
+System.import("app");
+```
+```TypeScript
+// app.ts
+import {Component, View, bootstrapWebWorker} from "angular2/web_worker/worker";
+@Component({
+ selector: "hello-world"
+})
+@View({
+ template: "Hello {{name}}
+})
+export class HelloWorld {
+ name: string = "Jane";
+}
+
+bootstrapWebWorker(HelloWorld);
+```
+There's a few important things to note here:
+* On the UI side we import all angular types from `angular2/web_worker/ui` and on the worker side we import from
+`angular2/web_worker/worker`. These modules include all the typings in the WebWorker bundle. By importing from
+these URLs instead of `angular2/angular2` we can statically ensure that our app does not reference a type that
+doesn't exist in the context it's mean to execute in. For example, if we tried to import DomRenderer in the Worker
+or NgFor on the UI we would get a compiler error.
+* The UI loads angular from the file `angular2/web_worker/ui.js` and the Worker loads angular from
+`angular2/web_worker/worker.js`. These bundles are created specifically for using WebWorkers and should be used
+instead of the normal angular2.js file. Both files contain subsets of the angular2 codebase that is designed to
+run specifically on the UI or Worker. Additionally, they contain the core messaging infrastructure used to
+communicate between the Worker and the UI. This messaging code is not in the standard angular2.js file.
+* We pass `loader.js` to bootstrap and not `app.ts`. You can think of `loader.js` as the `index.html` of the
+Worker. Since WebWorkers share no memory with the UI we need to reload the angular2 dependencies before
+bootstrapping our application. We do this with importScripts. Additionally, we need to do this in a different
+file than `app.ts` because our module loader (System.js in this example) has not been loaded yet, and `app.ts`
+will be compiled with a System.define call at the top.
+* The HelloWorld Component looks exactly like a normal Angular2 HelloWorld Component! The goal of WebWorker
+support was to allow as much of Angular to live in the worker as possible.
+As such, *most* angular2 components can be bootstrapped in a WebWorker with minimal to no changes required.
+
+For reference, here's the same HelloWorld example in Dart.
+```HTML
+
+
+
+
+
+
+```
+```Dart
+// index.dart
+import "package:angular2/web_worker/ui.dart";
+import "package:angular2/src/core/reflection/reflection.dart";
+import "package:angular2/src/core/reflection/reflection_capabilities.dart";
+
+main() {
+ reflector.reflectionCapabilities = new ReflectionCabilities();
+ bootstrap("app.dart");
+}
+```
+```Dart
+import "package:angular2/web_worker/worker.dart";
+import "package:angular2/src/core/reflection/reflection.dart";
+import "package:angular2/src/core/reflection/reflection_capabilities.dart";
+
+@Component(
+ selector: "hello-world"
+)
+@View(
+ template: "Hello {{name}}
"
+)
+class HelloWorld {
+ String name = "Jane";
+}
+
+main(List args, SendPort replyTo) {
+ reflector.reflectionCapabilities = new ReflectionCapabilities();
+ bootstrapWebWorker(replyTo, HelloWorld);
+}
+
+```
+This code is nearly the same as the TypeScript version with just a couple key differences:
+* We don't have a `loader.js` file. Dart applications don't need this file because you don't need a module loader.
+* We pass a `SendPort` to `bootstrapWebWorker`. Dart applications use the Isolate API, which communicates via
+Dart's Port abstraction. When you call `bootstrap` from the UI thread, angular starts a new Isolate to run
+your application logic. When Dart starts a new Isolate it passes a `SendPort` to that Isolate so that it
+can communicate with the Isolate that spawned it. You need to pass this `SendPort` to `bootstrapWebWorker`
+so that Angular can communicate with the UI.
+* You need to set up `ReflectionCapabilities` on both the UI and Worker. Just like writing non-concurrent
+Angular2 Dart applications you need to set up the reflector. You should not use Reflection in production,
+but should use the angular 2 transformer to remove it in your final JS code. Note there's currently a bug
+with running the transformer on your UI code (#3971). You can (and should) pass the file where you call
+`bootstrapWebWorker` as an entry point to the transformer, but you should not pass your UI index file
+to the transformer until that bug is fixed.
+
+## Writing WebWorker Compatible Components
+You can do almost everything in a WebWorker component that you can do in a typical Angular 2 Component.
+The main exception is that there is **no** DOM access from a WebWorker component. In Dart this means you can't
+import anything from `dart:html` and in JavaScript it means you can't use `document` or `window`. Instead you
+should use data bindings and if needed you can inject the `Renderer` along with your component's `ElementRef`
+directly into your component and use methods such as `setElementProperty`, `setElementAttribute`,
+`setElementClass`, `setElementStyle`, `invokeElementMethod`, and `setText`. Not that you **cannot** call
+`getNativeElementSync`. Doing so will always return `null` when running in a WebWorker.
+If you need DOM access see [Running Code on the UI](#running-code-on-the-ui).
+
+## WebWorker Design Overview
+When running your application in a WebWorker, the majority of the angular core along with your application logic
+runs on the worker. The two main components that run on the UI are the `Renderer` and the `RenderCompiler`. When
+running angular in a WebWorker the bindings for these two components are replaced by the `WebWorkerRenderer` and
+the `WebWorkerRenderCompiler`. When these components are used at runtime, they pass messages through the
+[MessageBroker](#messagebroker) instructing the UI to run the actual method and return the result. The
+[MessageBroker](#messagebroker) abstraction allows either side of the WebWorker boundary to schedule code to run
+on the opposite side and receive the result. You can use the [MessageBroker](#messagebroker)
+Additionally, the [MessageBroker](#messagebroker) sits on top of the [MessageBus](#messagebus).
+MessageBus is a low level abstraction that provides a language agnostic API for communicating with angular components across any runtime boundary such as `WebWorker <--> UI` communication, `UI <--> Server` communication,
+or `Window <--> Window` communication.
+
+See the diagram below for a high level overview of how this code is structured:
+
+![WebWorker Diagram](http://stanford.edu/~jteplitz/ng_2_worker.png)
+
+## Running Code on the UI
+If your application needs to run code on the UI, there are a few options. The easiest way is to use a
+CustomElement in your view. You can then register this custom element from your html file and run code in response
+to the element's lifecycle hooks. Note, Custom Elements are still experimental. See
+[MDN](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Custom_Elements) for the latest details on how
+to use them.
+
+If you require more robust communication between the WebWorker and the UI you can use the [MessageBroker](#using-the-messagebroker-in-your-application) or
+[MessageBus](#using-the-messagebus-in-your-application) directly.
+
+## MessageBus
+The MessageBus is a low level abstraction that provides a language agnostic API for communicating with angular components across any runtime boundary. It supports multiplex communication through the use of a channel
+abstraction.
+
+Angular currently includes two stable MessageBus implementations, which are used by default when you run your
+application inside a WebWorker.
+
+1. The `PostMessageBus` is used by JavaScript applications to communicate between a WebWorker and the UI.
+2. The `IsolateMessageBus` is used by Dart applications to communicate between a background Isolate and the UI.
+
+Angular also includes three experimental MessageBus implementations:
+
+1. The `WebSocketMessageBus` is a Dart MessageBus that lives on the UI and communicates with an angular
+application running on a server. It's intended to be used with either the `SingleClientServerMessageBus` or the
+`MultiClientServerMessageBus`.
+2. The `SingleClientServerMessageBus` is a Dart MessageBus that lives on a Dart Server. It allows an angular
+application to run on a server and communicate with a single browser that's running the `WebSocketMessageBus`.
+3. The `MultiClientServerMessageBus` is like the `SingleClientServerMessageBus` except it allows an arbitrary
+number of clients to connect to the server. It keeps all connected browsers in sync and if an event fires in
+any connected browser it propagates the result to all connected clients. This can be especially useful as a
+debugging tool, by allowing you to connect multiple browsers / devices to the same angular application,
+change the state of that application, and ensure that all the clients render the view correctly. Using these tools
+can make it easy to catch tricky browser compatibility issues.
+
+### Using the MessageBus in Your Application
+**Note**: If you want to pass custom messages between the UI and WebWorker, it's recommended you use the
+[MessageBroker](#using-the-messagebroker-in-your-application). However, if you want to control the messaging
+protocol yourself you can use the MessageBus directly.
+
+To use the MessageBus you need to initialize a new channel on both the UI and WebWorker.
+In TypeScript that would look like this:
+```TypeScript
+// index.ts, which is running on the UI.
+var instance = bootstrap("loader.js");
+var bus = instance.bus;
+bus.initChannel("My Custom Channel");
+```
+```TypeScript
+// background_index.ts, which is running on the WebWorker
+import {MessageBus} from 'angular2/web_worker/worker';
+@Component({...})
+@View({...})
+export class MyComponent {
+ constructor (bus: MessageBus) {
+ bus.initChannel("My CustomChannel");
+ }
+}
+```
+
+Once the channel has been initialized either side can use the `from` and `to` methods on the MessageBus to send
+and receive messages. Both methods return EventEmitter. Expanding on the example from earlier:
+```TypeScript
+// index.ts, which is running on the UI.
+import {bootstrap} from 'angukar2/web_worker/ui';
+var instance = bootstrap("loader.js");
+var bus = instance.bus;
+bus.initChannel("My Custom Channel");
+bus.to("My Custom Channel").next("hello from the UI");
+```
+```TypeScript
+// background_index.ts, which is running on the WebWorker
+import {MessageBus, Component, View} from 'angular2/web_worker/worker';
+@Component({...})
+@View({...})
+export class MyComponent {
+ constructor (bus: MessageBus) {
+ bus.initChannel("My Custom Channel");
+ bus.from("My Custom Channel").observer((message) => {
+ console.log(message); // will print "hello from the UI"
+ });
+ }
+}
+```
+
+This example is nearly identical in Dart, and is included below for reference:
+```Dart
+// index.dart, which is running on the UI.
+import 'package:angular2/web_workers/ui.dart';
+
+main() {
+ var instance = bootstrap("background_index.dart");
+ var bus = instance.bus;
+ bus.initChannel("My Custom Channel");
+ bus.to("My Custom Channel").add("hello from the UI");
+}
+
+```
+```Dart
+// background_index.dart, which is running on the WebWorker
+import 'package:angular2/web_worker/worker.dart';
+@Component(...)
+@View(...)
+class MyComponent {
+ MyComponent (MessageBus bus) {
+ bus.initChannel("My Custom Channel");
+ bus.from("My Custom Channel").listen((message) {
+ print(message); // will print "hello from the UI"
+ });
+ }
+}
+```
+The only substantial difference between these APIs in Dart and TypeScript is the different APIs for the
+`EventEmitter`.
+
+**Note** Because the messages passed through the MessageBus cross a WebWorker boundary, they must be serializable.
+If you use the MessageBus directly, you are responsible for serializing your messages.
+In JavaScript / TypeScript this means they must be serializable via JavaScript's
+[structured cloning algorithim](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm).
+
+In Dart this means they must be valid messages that can be passed through a
+[SendPort](https://api.dartlang.org/1.12.1/dart-isolate/SendPort/send.html).
+
+
+### MessageBus and Zones
+The MessageBus API includes support for [zones](http://www.github.com/angular/zone.js).
+A MessageBus can be attached to a specific zone (by calling `attachToZone`). Then specific channels can be
+specified to run in the zone when they are initialized.
+If a channel is running in the zone, that means that any events emitted from that channel will be executed within
+the given zone. For example, by default angular runs the EventDispatch channel inside the angular zone. That means
+when an event is fired from the DOM and received on the WebWorker the event handler automatically runs inside the
+angular zone. This is desired because after the event handler exits we want to exit the zone so that we trigger
+change detection. Generally, you want your channels to run inside the zone unless you have a good reason for why
+they need to run outside the zone.
+
+### Implementing and Using a Custom MessageBus
+**Note** Implementing and using a Custom MesageBus is experimental and requires importing from private APIs.
+
+If you want to drive your application from something other than a WebWorker you can implement a custom message
+bus. Implementing a custom message bus just means creating a class that fulfills the API specified by the
+abstract MessageBus class.
+
+If you're implementing your MessageBus in Dart you can extend the `GenericMessageBus` class included in angular.
+if you do this, you don't need to implement zone or channel support yourself. You only need to implement a
+`MessageBusSink` that extends `GenericMessageBusSink` and a `MessageBusSource` that extends
+`GenericMessageBusSource`. The `MessageBusSink` must override the `sendMessages` method. This method is
+given a list of serialized messages that it is required to send through the sink.
+The `MessageBusSource` needs to provide a [Stream](https://api.dartlang.org/1.12.1/dart-async/Stream-class.html)
+of incoming messages (either by passing the stream to `GenericMessageBusSource's` constructor or by calling
+attachTo() with the stream). It also needs to override the abstract `decodeMessages` method. This method is
+given a List of serialized messages received by the source and should perform any decoding work that needs to be
+done before the application can read the messages.
+
+For example, if your MessageBus sends and receives JSON data you would do the following:
+```Dart
+import 'package:angular2/src/web_workers/shared/generic_message_bus.dart';
+import 'dart:convert';
+
+class JsonMessageBusSink extends GenericMessageBusSink {
+ @override
+ void sendMessages(List messages) {
+ String encodedMessages = JSON.encode(messages);
+ // Send encodedMessages here
+ }
+}
+
+class JsonMessageBusSource extends GenericMessageBuSource {
+ JsonMessageBusSource(Stream incomingMessages) : super (incomingMessages);
+
+ @override
+ List decodeMessages(dynamic messages) {
+ return JSON.decode(messages);
+ }
+}
+```
+
+Once you've implemented your custom MessageBus in either TypeScript or Dart you can tell angular to use it like
+so:
+In TypeScript:
+```TypeScript
+// index.ts, running on the UI side
+import {bootstrapUICommon} from 'angular2/src/web_workers/ui/impl';
+var bus = new MyAwesomeMessageBus();
+bootstrapUICommon(bus);
+```
+```TypeScript
+// background_index.ts, running on the application side
+import {bootstrapWebWorkerCommon} from 'angular2/src/web_workers/worker/application_common';
+import {MyApp} from './app';
+var bus = new MyAwesomeMessageBus();
+bootstrapWebWorkerCommon(MyApp, bus);
+```
+In Dart:
+```Dart
+// index.dart, running on the UI side
+import 'package:angular2/src/web_workers/ui/impl.dart' show bootstrapUICommon;
+import "package:angular2/src/core/reflection/reflection.dart";
+import "package:angular2/src/core/reflection/reflection_capabilities.dart";
+
+main() {
+ reflector.reflectionCapabilities = new ReflectionCapabilities();
+ var bus = new MyAwesomeMessageBus();
+ bootstrapUiCommon(bus);
+}
+```
+```Dart
+// background_index.dart, running on the application side
+import "package:angular2/src/web_workers/worker/application_common.dart" show bootstrapWebWorkerCommon;
+import "package:angular2/src/core/reflection/reflection.dart";
+import "package:angular2/src/core/reflection/reflection_capabilities.dart";
+import "./app.dart" show MyApp;
+
+main() {
+ reflector.reflectionCapabilities = new ReflectionCapabilities();
+ var bus = new MyAwesomeMessageBus();
+ bootstrapWebWorkerCommon(MyApp, bus);
+}
+```
+Notice how we call `bootstrapUICommon` instead of `bootstrap` from the UI side. `bootstrap` spans a new WebWorker
+/ Isolate and attaches the default angular MessageBus to it. If you're using a custom MessageBus you are
+responsible for setting up the application side and initiating communication with it. `bootstrapUICommon` assumes
+that the given MessageBus is already set up and can communicate with the application.
+Similarly, we call `bootstrapWebWorkerCommon` instead of `boostrapWebWorker` from the application side. This is
+because `bootstrapWebWorker` assumes you're using the default angular MessageBus and initializes a new one for you.
+
+## MessageBroker
+The MessageBroker is a higher level messaging abstraction that sits on top of the MessageBus. It is used when you
+want to execute code on the other side of a runtime boundary and may want to receive the result.
+There are two types of MessageBrokers. The `ServiceMessageBroker` is used by the side that actually performs
+an operation and may return a result. Conversely, the `ClientMessageBroker` is used by the side that requests that
+an operation be performed and may want to receive the result.
+
+### Using the MessageBroker In Your Application
+To use MessageBrokers in your application you must initialize both a `ClientMessageBroker` and a
+`ServiceMessageBroker` on the same channel. You can then register methods that the `ServiceMessageBroker` should
+listen the instruct the `ClientMessageBroker` to run those methods. Below is a lightweight example of using
+MessageBrokers in an application. For a more complete example, check out the `WebWorkerRenderer` and
+`MessageBasedRenderer` inside the Angular WebWorker code.
+
+#### Using the MessageBroker in TypeScript
+```TypeScript
+// index.ts, which is running on the UI with a method that we want to expose to a WebWorker
+import {bootstrap} from 'angular2/web_worker/ui';
+
+var instance = bootstrap("loader.js");
+var broker = instance.app.createServiceMessageBroker("My Broker Channel");
+
+// assume we have some function doCoolThings that takes a string argument and returns a Promise
+broker.registerMethod("awesomeMethod", [PRIMITIVE], (arg1: string) => doCoolThing(arg1), PRIMITIVE);
+```
+```TypeScript
+// background.ts, which is running on a WebWorker and wants to execute a method on the UI
+import {Component, View, ClientMessageBrokerFactory, PRIMITIVE, UiArguments, FnArgs}
+from 'angular2/web_worker/worker';
+
+@Component(...)
+@View(...)
+export class MyComponent {
+ constructor(brokerFactory: ClientMessageBrokerFactory) {
+ var broker = brokerFactory.createMessageBroker("My Broker Channel");
+
+ var arguments = [new FnArg(value, PRIMITIVE)];
+ var methodInfo = new UiArguments("awesomeMethod", arguments);
+ broker.runOnService(methodInfo, PRIMTIVE).then((result: string) => {
+ // result will be equal to the return value of doCoolThing(value) that ran on the UI.
+ });
+ }
+}
+```
+#### Using the MessageBroker in Dart
+```Dart
+// index.dart, which is running on the UI with a method that we want to expose to a WebWorker
+import 'package:angular2/web_worker/ui.dart';
+
+main() {
+ var instance = bootstrap("background.dart");
+ var broker = instance.app.createServiceMessageBroker("My Broker Channel");
+
+ // assume we have some function doCoolThings that takes a String argument and returns a Future
+ broker.registerMethod("awesomeMethod", [PRIMITIVE], (String arg1) => doCoolThing(arg1), PRIMITIVE);
+}
+
+```
+```Dart
+// background.dart, which is running on a WebWorker and wants to execute a method on the UI
+import 'package:angular2/web_worker/worker.dart';
+
+@Component(...)
+@View(...)
+class MyComponent {
+ MyComponent(ClientMessageBrokerFactory brokerFactory) {
+ var broker = brokerFactory.createMessageBroker("My Broker Channel");
+
+ var arguments = [new FnArg(value, PRIMITIVE)];
+ var methodInfo = new UiArguments("awesomeMethod", arguments);
+ broker.runOnService(methodInfo, PRIMTIVE).then((String result) {
+ // result will be equal to the return value of doCoolThing(value) that ran on the UI.
+ });
+ }
+}
+```
+Both the client and the service create new MessageBrokers and attach them to the same channel.
+The service then calls `registerMethod` to register the method that it wants to listen to. Register method takes
+four arguments. The first is the name of the method, the second is the Types of that method's parameters, the
+third is the method itself, and the fourth (which is optional) is the return Type of that method.
+The MessageBroker handles serializing / deserializing your parameters and return types using angular's serializer.
+However, at the moment the serializer only knows how to serialize angular classes like those used by the Renderer.
+If you're passing anything other than those types around in your application you can handle serialization yourself
+and then use the `PRIMITIVE` type to tell the MessageBroker to avoid serializing your data.
+
+The last thing that happens is that the client calls `runOnService` with the name of the method it wants to run,
+a list of that method's arguments and their types, and (optionally) the expected return type.