diff --git a/lib/src/barback/dart2js_transformer.dart b/lib/src/barback/dart2js_transformer.dart
index 7c7f53944b6357219fc6f4412ac444b1acfa60f9..16411174ef51356dd81dd9e4c6daf89dc828ea72 100644
--- a/lib/src/barback/dart2js_transformer.dart
+++ b/lib/src/barback/dart2js_transformer.dart
@@ -20,6 +20,7 @@ import '../../../../compiler/implementation/source_file.dart';
 import '../barback.dart';
 import '../dart.dart' as dart;
 import '../io.dart';
+import '../pool.dart';
 import '../utils.dart';
 import 'build_environment.dart';
 
@@ -32,18 +33,15 @@ final _validOptions = new Set<String>.from([
 /// A [Transformer] that uses dart2js's library API to transform Dart
 /// entrypoints in "web" to JavaScript.
 class Dart2JSTransformer extends Transformer implements LazyTransformer {
-  final BuildEnvironment _environment;
-  final BarbackSettings _settings;
-
-  /// If this is non-null, then the transformer is currently being applied, so
-  /// subsequent calls to [apply] will wait for this to finish before
-  /// proceeding.
+  /// We use this to ensure that only one compilation is in progress at a time.
   ///
   /// Dart2js uses lots of memory, so if we try to actually run compiles in
-  /// parallel, it takes down the VM. Instead, the transformer will force
-  /// all applies to be sequential. The tracking bug to do something better
+  /// parallel, it takes down the VM. The tracking bug to do something better
   /// is here: https://code.google.com/p/dart/issues/detail?id=14730.
-  Future _running;
+  static final _pool = new Pool(1);
+
+  final BuildEnvironment _environment;
+  final BarbackSettings _settings;
 
   Dart2JSTransformer.withSettings(this._environment, this._settings) {
     var invalidOptions = _settings.configuration.keys.toSet()
@@ -70,72 +68,60 @@ class Dart2JSTransformer extends Transformer implements LazyTransformer {
   }
 
   Future apply(Transform transform) {
-    transform.logger.info("Compiling ${transform.primaryInput.id}...");
+    var stopwatch = new Stopwatch();
 
     // Wait for any ongoing apply to finish first.
-    // TODO(rnystrom): If there are multiple simultaneous compiles, this will
-    // resume and pause them repeatedly. It still serializes them correctly,
-    // but it might be cleaner to use a real queue.
-    // TODO(rnystrom): Add a test that this is functionality is helpful.
-    if (_running != null) {
-      return _running.then((_) => apply(transform));
-    }
-
-    var completer = new Completer();
-    _running = completer.future;
+    return _pool.withResource(() {
+      transform.logger.info("Compiling ${transform.primaryInput.id}...");
+      stopwatch.start();
+
+      return transform.primaryInput.readAsString().then((code) {
+        try {
+          var id = transform.primaryInput.id;
+          var name = id.path;
+          if (id.package != _environment.rootPackage.name) {
+            name += " in ${id.package}";
+          }
+
+          var parsed = parseCompilationUnit(code, name: name);
+          if (!dart.isEntrypoint(parsed)) return null;
+        } on AnalyzerErrorGroup catch (e) {
+          transform.logger.error(e.message);
+          return null;
+        }
 
-    var stopwatch = new Stopwatch();
-    stopwatch.start();
+        var provider = new _BarbackCompilerProvider(_environment, transform);
 
-    return transform.primaryInput.readAsString().then((code) {
-      try {
+        // Create a "path" to the entrypoint script. The entrypoint may not
+        // actually be on disk, but this gives dart2js a root to resolve
+        // relative paths against.
         var id = transform.primaryInput.id;
-        var name = id.path;
-        if (id.package != _environment.rootPackage.name) {
-          name += " in ${id.package}";
-        }
-
-        var parsed = parseCompilationUnit(code, name: name);
-        if (!dart.isEntrypoint(parsed)) return null;
-      } on AnalyzerErrorGroup catch (e) {
-        transform.logger.error(e.message);
-        return null;
-      }
 
-      var provider = new _BarbackCompilerProvider(_environment, transform);
-
-      // Create a "path" to the entrypoint script. The entrypoint may not
-      // actually be on disk, but this gives dart2js a root to resolve
-      // relative paths against.
-      var id = transform.primaryInput.id;
-
-      var entrypoint = path.join(_environment.graph.packages[id.package].dir,
-          id.path);
-
-      // TODO(rnystrom): Should have more sophisticated error-handling here.
-      // Need to report compile errors to the user in an easily visible way.
-      // Need to make sure paths in errors are mapped to the original source
-      // path so they can understand them.
-      return Chain.track(dart.compile(
-          entrypoint, provider,
-          commandLineOptions: _configCommandLineOptions,
-          checked: _configBool('checked'),
-          minify: _configBool(
-              'minify', defaultsTo: _settings.mode == BarbackMode.RELEASE),
-          verbose: _configBool('verbose'),
-          environment: _configEnvironment,
-          packageRoot: path.join(_environment.rootPackage.dir,
-                                 "packages"),
-          analyzeAll: _configBool('analyzeAll'),
-          suppressWarnings: _configBool('suppressWarnings'),
-          suppressHints: _configBool('suppressHints'),
-          terse: _configBool('terse'))).then((_) {
-        stopwatch.stop();
-        transform.logger.info("Took ${stopwatch.elapsed} to compile $id.");
+        var entrypoint = path.join(_environment.graph.packages[id.package].dir,
+            id.path);
+
+        // TODO(rnystrom): Should have more sophisticated error-handling here.
+        // Need to report compile errors to the user in an easily visible way.
+        // Need to make sure paths in errors are mapped to the original source
+        // path so they can understand them.
+        return Chain.track(dart.compile(
+            entrypoint, provider,
+            commandLineOptions: _configCommandLineOptions,
+            checked: _configBool('checked'),
+            minify: _configBool(
+                'minify', defaultsTo: _settings.mode == BarbackMode.RELEASE),
+            verbose: _configBool('verbose'),
+            environment: _configEnvironment,
+            packageRoot: path.join(_environment.rootPackage.dir,
+                                   "packages"),
+            analyzeAll: _configBool('analyzeAll'),
+            suppressWarnings: _configBool('suppressWarnings'),
+            suppressHints: _configBool('suppressHints'),
+            terse: _configBool('terse'))).then((_) {
+          stopwatch.stop();
+          transform.logger.info("Took ${stopwatch.elapsed} to compile $id.");
+        });
       });
-    }).whenComplete(() {
-      completer.complete();
-      _running = null;
     });
   }