diff --git a/migrate.install b/migrate.install
index e8d730f..94a9536 100644
--- a/migrate.install
+++ b/migrate.install
@@ -17,6 +17,23 @@ function migrate_schema() {
 function migrate_schema_status() {
   return array(
     'description' => 'Status information for migrations',
+    'export' => array(
+      'key' => 'machine_name',
+      'key name' => 'Name',
+      'primary key' => 'machine_name',
+      'identifier' => 'migrate', // Exports will be defined as $preset
+      'default hook' => 'migrate_preset',  // Function hook name.
+      'delete callback' => 'migrate_ctools_delete',
+      'load callback' => 'migrate_ctools_load',
+      'save callback' => 'migrate_ctools_save',
+      'export callback' => 'migrate_ctools_export',
+      'api' => array(
+        'owner' => 'migrate',
+        'api' => 'migrate',  // Base name for api include files.
+        'minimum_version' => 1,
+        'current_version' => 1,
+      ),
+    ),
     'fields' => array(
       'machine_name' => array(
         'type' => 'varchar',
diff --git a/migrate.module b/migrate.module
index 7d9bf89..9dd41d3 100644
--- a/migrate.module
+++ b/migrate.module
@@ -569,3 +569,179 @@ function migrate_module_implements_alter(&$implementation, $hook) {
     }
   }
 }
+
+
+/* Instead of completely deleting the record, we need to overwrite it with the
+ * code version instead. this needs to apply to field mappings too.
+ *
+ */
+function migrate_ctools_delete(&$object) {
+  $value = is_object($object) ? $object->machine_name : $object;
+  // Delete the migration plan.
+  db_delete('migrate_status')
+    ->condition('machine_name', $value)
+    ->execute();
+  // Delete the field mappings.
+  db_delete('migrate_field_mapping')
+    ->condition('machine_name', $value)
+    ->execute();
+
+  $defaults = _ctools_export_get_defaults('migrate_status', $object->machine_name);
+
+  ctools_export_crud_save('migrate_status', $defaults[$object->machine_name]);
+}
+
+/** load information about a migration including fields */
+function migrate_ctools_load($machine_name) {
+
+  foreach((array)$machine_name as $name) {
+    $ms_query = db_select("migrate_status", "ms")
+      ->fields('ms')
+      ->condition('machine_name', $name)
+      ->execute();
+
+    foreach ($ms_query as $result) {
+      $result->arguments = unserialize($result->arguments);
+
+      $query = db_select("migrate_field_mapping", 'mf')
+        ->fields('mf', array())
+        ->condition('machine_name', $name)
+        ->orderBy('destination_field', 'asc')
+        ->execute();
+
+      foreach ($query as $field) {
+        unset($field->fmid);
+        $result->fields[$field->destination_field] = $field;
+      }
+      $results[$name] = $result;
+    }
+  }
+  // We never want this to be an "in code only" export. It must exist in the DB.
+  return $results[$machine_name];
+}
+
+function migrate_ctools_save($object) {
+  // Import the data for the migration fields into the DB first.
+  db_delete("migrate_field_mapping")
+    ->condition('machine_name', $object->machine_name)
+    ->execute();
+  foreach($object->fields as $field) {
+    $field->options = unserialize($field->options);
+    drupal_write_record('migrate_field_mapping', $field);
+  }
+  // Remove the fields key to avoid throwing off the write to migration_status.
+  unset($object->fields);
+
+  db_delete("migrate_status")
+    ->condition('machine_name', $object->machine_name)
+    ->execute();
+
+  drupal_write_record('migrate_status', $object);
+}
+
+/**
+ * This code was taken almost verbatim from the ctools_crud_export function. the
+ * only addition here is a hack to ensure that 'fields' get composed in the
+ * rendered output. This can probably be done better with a direct rendering but
+ * this works as-is.
+ * @param $object
+ * @param string $indent
+ * @param null $identifier
+ * @param array $additions
+ * @param array $additions2
+ * @return string
+ */
+function migrate_ctools_export($object, $indent = '', $identifier = NULL, $additions = array(), $additions2 = array()) {
+  $schema = ctools_export_get_schema('migrate_status');
+  // Add a field named 'fields' to the schema to get ctools to export the loaded
+  // list of migration field mappings.
+  $schema['fields']['fields'] = array('type' => "field mapping list");
+  if (!isset($identifier)) {
+    $identifier = $schema['export']['identifier'];
+  }
+
+  $output = $indent . '$' . $identifier . ' = new ' . get_class($object) . "();\n";
+
+  if ($schema['export']['can disable']) {
+    $output .= $indent . '$' . $identifier . '->disabled = FALSE; /* Edit this to true to make a default ' . $identifier . ' disabled initially */' . "\n";
+  }
+  if (!empty($schema['export']['api']['current_version'])) {
+    $output .= $indent . '$' . $identifier . '->api_version = ' . $schema['export']['api']['current_version'] . ";\n";
+  }
+  // Put top additions here:
+  foreach ($additions as $field => $value) {
+    $output .= $indent . '$' . $identifier . '->' . $field . ' = ' . ctools_var_export($value, $indent) . ";\n";
+  }
+
+  $fields = $schema['fields'];
+  if (!empty($schema['join'])) {
+    foreach ($schema['join'] as $join) {
+      if (!empty($join['load'])) {
+        foreach ($join['load'] as $join_field) {
+          $fields[$join_field] = $join['fields'][$join_field];
+        }
+      }
+    }
+  }
+
+  // Go through our schema and joined tables and build correlations.
+  foreach ($fields as $field => $info) {
+    if (!empty($info['no export'])) {
+      continue;
+    }
+    if (!isset($object->$field)) {
+      if (isset($info['default'])) {
+        $object->$field = $info['default'];
+      }
+      else {
+        $object->$field = '';
+      }
+    }
+
+    // Note: This is the *field* export callback, not the table one!
+    if (!empty($info['export callback']) && function_exists($info['export callback'])) {
+      $output .= $indent . '$' . $identifier . '->' . $field . ' = ' . $info['export callback']($object, $field, $object->$field, $indent) . ";\n";
+    }
+    else {
+      $value = $object->$field;
+      if ($info['type'] == 'int') {
+        if (isset($info['size']) && $info['size'] == 'tiny') {
+          $info['boolean'] = (!isset($info['boolean'])) ? $schema['export']['boolean'] : $info['boolean'];
+          $value = ($info['boolean']) ? (bool) $value : (int) $value;
+        }
+        else {
+          $value = (int) $value;
+        }
+      }
+      $output .= $indent . '$' . $identifier . '->' . $field . ' = ' . ctools_var_export($value, $indent) . ";\n";
+    }
+  }
+
+  // And bottom additions here
+  foreach ($additions2 as $field => $value) {
+    $output .= $indent . '$' . $identifier . '->' . $field . ' = ' . ctools_var_export($value, $indent) . ";\n";
+  }
+
+  return $output;
+
+}
+
+/** override how features reverts migrate components */
+function migrate_status_features_revert($module, $component) {
+  $schema = ctools_export_get_schema('migrate_status');
+  $export = $schema['export'];
+  if ($objects = features_get_default($component, $module)) {
+    foreach ($objects as $name => $object) {
+      // Some things (like views) do not use the machine name as key
+      // and need to be loaded explicitly in order to be deleted.
+
+      // instead of getting the generic value that may come from the db, we want
+      // to specifically get it from code
+      $defaults = _ctools_export_get_defaults('migrate_status', $export);
+      $object = $defaults[$name];
+      if ($object) {
+        migrate_ctools_save($object);
+      }
+    }
+  }
+}
\ No newline at end of file
