diff --git a/doc/configuration.md b/doc/configuration.md
index ae6502b4ecb3ac1a7c641e62cc15097de78732d2..7f294429b4859f2f38dcda447e8571c9b7109db8 100644
--- a/doc/configuration.md
+++ b/doc/configuration.md
@@ -30,6 +30,7 @@ tags:
   * [`chain_stack_traces`](#chain_stack_traces)
   * [`js_trace`](#js_trace)
   * [`skip`](#skip)
+  * [`retry`](#retry)
   * [`test_on`](#test_on)
 * [Runner Configuration](#runner-configuration)
   * [`paths`](#paths)
@@ -139,6 +140,19 @@ tags:
 This field is not supported in the
 [global configuration file](#global-configuration).
 
+### `retry`
+
+This int field controls how many times a test is retried upon failure. 
+
+```yaml
+tags:
+  chrome:
+    retry: 3 # Retry chrome failures 3 times.
+```
+
+This field is not supported in the
+[global configuration file](#global-configuration).
+
 ### `test_on`
 
 This field declares which platforms a test supports. It takes a
diff --git a/lib/src/runner/configuration.dart b/lib/src/runner/configuration.dart
index 1d89e30c217c7aa1a1e2d9310782a38e86f8e086..3356f5370d96bf429c9f076545599b35c96938ef 100644
--- a/lib/src/runner/configuration.dart
+++ b/lib/src/runner/configuration.dart
@@ -216,6 +216,7 @@ class Configuration {
       bool verboseTrace,
       bool chainStackTraces,
       bool skip,
+      int retry,
       String skipReason,
       PlatformSelector testOn,
       Iterable<String> addTags}) {
@@ -253,6 +254,7 @@ class Configuration {
             verboseTrace: verboseTrace,
             chainStackTraces: chainStackTraces,
             skip: skip,
+            retry: retry,
             skipReason: skipReason,
             testOn: testOn,
             addTags: addTags));
diff --git a/lib/src/runner/configuration/load.dart b/lib/src/runner/configuration/load.dart
index 597fb35629bc735f310f3998d9598f4a6c2cf22f..00e89ad60ac8c1bb8b1952fb17b572c6c81bbb46 100644
--- a/lib/src/runner/configuration/load.dart
+++ b/lib/src/runner/configuration/load.dart
@@ -124,6 +124,7 @@ class _ConfigurationLoader {
   Configuration _loadLocalTestConfig() {
     if (_global) {
       _disallow("skip");
+      _disallow("retry");
       _disallow("test_on");
       _disallow("add_tags");
       _disallow("tags");
@@ -150,8 +151,11 @@ class _ConfigurationLoader {
         value: (valueNode) =>
             _nestedConfig(valueNode, "tag value", runnerConfig: false));
 
+    var retry = _getNonNegativeInt("retry");
+
     return new Configuration(
             skip: skip,
+            retry: retry,
             skipReason: skipReason,
             testOn: testOn,
             addTags: addTags)
@@ -290,6 +294,10 @@ class _ConfigurationLoader {
   /// Asserts that [field] is an int and returns its value.
   int _getInt(String field) => _getValue(field, "int", (value) => value is int);
 
+  /// Asserts that [field] is a non-negative int and returns its value.
+  int _getNonNegativeInt(String field) => _getValue(
+      field, "non-negative int", (value) => value is int && value >= 0);
+
   /// Asserts that [field] is a boolean and returns its value.
   bool _getBool(String field) =>
       _getValue(field, "boolean", (value) => value is bool);
diff --git a/lib/src/runner/configuration/suite.dart b/lib/src/runner/configuration/suite.dart
index d4541e8059d4bcb02e9d4040f0f62f8cdd29138e..47aae094efa4b18dd7ec5781549ca5f0d4b21a6b 100644
--- a/lib/src/runner/configuration/suite.dart
+++ b/lib/src/runner/configuration/suite.dart
@@ -135,6 +135,7 @@ class SuiteConfiguration {
       bool verboseTrace,
       bool chainStackTraces,
       bool skip,
+      int retry,
       String skipReason,
       PlatformSelector testOn,
       Iterable<String> addTags}) {
@@ -154,6 +155,7 @@ class SuiteConfiguration {
             verboseTrace: verboseTrace,
             chainStackTraces: chainStackTraces,
             skip: skip,
+            retry: retry,
             skipReason: skipReason,
             testOn: testOn,
             tags: addTags));
@@ -258,6 +260,7 @@ class SuiteConfiguration {
       bool verboseTrace,
       bool chainStackTraces,
       bool skip,
+      int retry,
       String skipReason,
       PlatformSelector testOn,
       Iterable<String> addTags}) {
@@ -277,6 +280,7 @@ class SuiteConfiguration {
             verboseTrace: verboseTrace,
             chainStackTraces: chainStackTraces,
             skip: skip,
+            retry: retry,
             skipReason: skipReason,
             testOn: testOn,
             tags: addTags));
diff --git a/pubspec.yaml b/pubspec.yaml
index 944856f6deeeed10e28eb6cff0d71865283eea1c..343694da368a6fde64e15e9bcaff7308dd839624 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
 name: test
-version: 0.12.21
+version: 0.12.22-dev
 author: Dart Team <misc@dartlang.org>
 description: A library for writing dart unit tests.
 homepage: https://github.com/dart-lang/test
diff --git a/test/runner/configuration/global_test.dart b/test/runner/configuration/global_test.dart
index 8984ab791b5d74831306afb78c1d345c343c0108..69d290131b6a29472edfafaacda683da8835f1d7 100644
--- a/test/runner/configuration/global_test.dart
+++ b/test/runner/configuration/global_test.dart
@@ -105,6 +105,7 @@ void main() {
   group("disallows local-only configuration:", () {
     for (var field in [
       "skip",
+      "retry",
       "test_on",
       "paths",
       "filename",
diff --git a/test/runner/configuration/top_level_error_test.dart b/test/runner/configuration/top_level_error_test.dart
index b770d94fc668200874247208b0008bde1c2ae12e..086ccfb6a8cb419585c7b9da33c146461162c193 100644
--- a/test/runner/configuration/top_level_error_test.dart
+++ b/test/runner/configuration/top_level_error_test.dart
@@ -45,6 +45,24 @@ void main() {
     test.shouldExit(exit_codes.data);
   });
 
+  test("rejects an invalid retry", () {
+    d.file("dart_test.yaml", JSON.encode({"retry": "flup"})).create();
+
+    var test = runTest(["test.dart"]);
+    test.stderr.expect(
+        containsInOrder(["retry must be a non-negative int", "^^^^^^"]));
+    test.shouldExit(exit_codes.data);
+  });
+
+  test("rejects an negative retry values", () {
+    d.file("dart_test.yaml", JSON.encode({"retry": -1})).create();
+
+    var test = runTest(["test.dart"]);
+    test.stderr
+        .expect(containsInOrder(["retry must be a non-negative int", "^^"]));
+    test.shouldExit(exit_codes.data);
+  });
+
   test("rejects an invalid js_trace", () {
     d.file("dart_test.yaml", JSON.encode({"js_trace": "flup"})).create();
 
diff --git a/test/runner/configuration/top_level_test.dart b/test/runner/configuration/top_level_test.dart
index 92fc36ed6fc9f75dc0fafd4bc0cc8c1c17a96888..b55e32cad410da3c08129e30c90b619d9f12e155 100644
--- a/test/runner/configuration/top_level_test.dart
+++ b/test/runner/configuration/top_level_test.dart
@@ -205,6 +205,34 @@ void main() {
     test.shouldExit(1);
   }, tags: 'chrome');
 
+  test("retries tests with retry: 1", () {
+    d.file("dart_test.yaml", JSON.encode({"retry": 1})).create();
+
+    d
+        .file(
+            "test.dart",
+            """
+      import 'package:test/test.dart';
+      import 'dart:async';
+
+      var attempt = 0;
+      void main() {
+        test("test", () {
+          attempt++;
+          if(attempt <= 1) {
+            throw 'Failure!';
+          }
+        });
+      }
+
+    """)
+        .create();
+
+    var test = runTest(["test.dart"]);
+    test.stdout.expect(consumeThrough(contains('+1: All tests passed')));
+    test.shouldExit(0);
+  });
+
   test("skips tests with skip: true", () {
     d.file("dart_test.yaml", JSON.encode({"skip": true})).create();