diff --git a/domain.admin.inc b/domain.admin.inc
index 8aa394f..2a9c914 100644
--- a/domain.admin.inc
+++ b/domain.admin.inc
@@ -526,7 +526,7 @@ function domain_form_validate($form, &$form_state) {
 function domain_form_submit($form, &$form_state) {
   $values = domain_values_from_form_state($form_state);
   // Set the proper message.
-  if (!empty($values['domain_id']) || $values['domain_id'] == 0) {
+  if (!empty($values['domain_id'])) {
     $message = t('Domain record updated.');
   }
   else {
diff --git a/domain.install b/domain.install
index 1f79b66..70111e6 100644
--- a/domain.install
+++ b/domain.install
@@ -19,19 +19,38 @@ function domain_schema() {
   $schema['domain'] = array(
     'description' => 'The base table for domain records',
     'fields' => array(
-      'domain_id' => array('type' => 'serial', 'not null' => TRUE, 'description' => 'Primary key'),
+      'domain_id' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0, 'description' => 'Domain numeric id.'),
       'subdomain' => array('type' => 'varchar', 'length' => '255', 'not null' => TRUE, 'default' => '', 'description' => 'Registered DNS entry, will match HTTP_HOST requests'),
       'sitename' => array('type' => 'varchar', 'length' => '255', 'not null' => TRUE, 'default' => '', 'description' => 'Site display name'),
       'scheme' => array('type' => 'varchar', 'length' => '8', 'not null' => TRUE, 'default' => 'http', 'description' => 'Protocol'),
       'valid' => array('type' => 'varchar', 'length' => '1', 'not null' => TRUE, 'default' => '1', 'description' => 'Active status'),
       'weight' => array('type' => 'int', 'unsigned' => FALSE, 'not null' => TRUE, 'default' => 0, 'description' => 'Sort order'),
-      'is_default' => array('type' => 'int', 'size' => 'tiny', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0, 'description' => 'Indicates primary domain')),
-    'primary key' => array('domain_id'),
+      'is_default' => array('type' => 'int', 'size' => 'tiny', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0, 'description' => 'Indicates primary domain'),
+      'machine_name' => array('type' => 'varchar', 'length' => '40', 'not null' => TRUE, 'default' => '', 'description' => 'The machine name for this domain.')),
+    'primary key' => array('machine_name'),
     'indexes' => array(
+      'domain_id' => array('domain_id'),
       'subdomain' => array('subdomain'),
       'weight' => array('weight'),
       'is_default' => array('is_default'),
     ),
+    'foreign_keys' => array(
+      'domain_id' => array('domain_export' => 'domain_id'),
+    ),
+    'export' => array(
+      'identifier' => 'domain',
+      'key' => 'machine_name',
+      'primary key' => 'machine_name',
+      'admin_title' => 'subdomain',
+      'default hook' => 'domain_default_domains',
+      'api' => array(
+        'owner' => 'domain',
+        'api' => 'domain',
+        'minimum_version' => 3,
+        'current_version' => 3,
+      ),
+      'can disable' => FALSE,
+    ),
   );
   $schema['domain_access'] = array(
     'description' => 'Stores domain information for each node',
@@ -58,6 +77,17 @@ function domain_schema() {
       'domain_id' => array('domain' => 'domain_id'),
     ),
   );
+  $schema['domain_export'] = array(
+    'description' => 'Stores canonical machine names for domains.',
+    'fields' => array(
+      'domain_id' => array('type' => 'serial', 'description' => 'Domain id. Automatic master key.'),
+      'machine_name' => array('type' => 'varchar', 'length' => '40', 'not null' => TRUE, 'default' => '', 'description' => 'The machine name for this domain.'),
+      'status' => array('type' => 'int', 'size' => 'tiny', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0, 'description' => 'Stores whether domain is loaded from code.')),
+    'primary key' => array('machine_name'),
+    'indexes' => array(
+      'domain_id' => array('domain_id')
+    ),
+  );
   return $schema;
 }
 
@@ -105,7 +135,7 @@ function domain_uninstall() {
 /**
  * Update block deltas to Drupal 7.
  */
-function domain_update_7000() {
+function domain_update_7000(&$sandbox) {
   // Get an array of the renamed block deltas, organized by module.
   $renamed_deltas = array(
     'domain' => array(
@@ -120,7 +150,7 @@ function domain_update_7000() {
 /**
  * Change the edit and delete permissions.
  */
-function domain_update_7001() {
+function domain_update_7001(&$sandbox) {
   db_update('role_permission')
     ->condition('permission', 'edit domain nodes')
     ->fields(array('permission' => 'edit domain content'))
@@ -135,7 +165,7 @@ function domain_update_7001() {
 /**
  * Add sorting to domains.
  */
-function domain_update_7300() {
+function domain_update_7300(&$sandbox) {
   if (db_field_exists('domain', 'weight')) {
     return('No update required');
   }
@@ -148,7 +178,7 @@ function domain_update_7300() {
 /**
  * Add default domain flag and weight the default higher.
  */
-function domain_update_7301() {
+function domain_update_7301(&$sandbox) {
   if (db_field_exists('domain', 'is_default')) {
     return('No update required');
   }
@@ -164,7 +194,7 @@ function domain_update_7301() {
 /**
  * Add an index on {domain}.is_default.
  */
-function domain_update_7302() {
+function domain_update_7302(&$sandbox) {
   if (!db_index_exists('domain', 'is_default')) {
     db_add_index('domain', 'is_default', array('is_default'));
   }
@@ -173,7 +203,7 @@ function domain_update_7302() {
 /**
  * Remove the zero record from the database.
  */
-function domain_update_7303() {
+function domain_update_7303(&$sandbox) {
   // We grab the default domain, remove it from the database, and
   // then re-save it into the table, using the new value as the default domain.
   $default = db_query("SELECT * FROM {domain} WHERE domain_id = 0")->fetchAssoc();
@@ -214,3 +244,70 @@ function domain_update_7303() {
   // Update message.
   return t('Domain Access updated successfully');
 }
+
+/**
+ * Allow domains to be made exportable.
+ */
+function domain_update_7304(&$sandbox) {
+  if (db_table_exists('domain_export')) {
+    return t('{domain_export} table exists.');
+  }
+  $schema = array(
+    'description' => 'Stores canonical machine names for domains.',
+    'fields' => array(
+      'domain_id' => array('type' => 'serial', 'description' => 'Domain id. Automatic master key.'),
+      'machine_name' => array('type' => 'varchar', 'length' => '40', 'not null' => TRUE, 'default' => '', 'description' => 'The machine name for this domain.'),
+      'status' => array('type' => 'int', 'size' => 'tiny', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0, 'description' => 'Stores whether domain is loaded from code.')),
+    'primary key' => array('machine_name'),
+    'indexes' => array(
+      'domain_id' => array('domain_id')
+    ),
+  );
+  db_create_table('domain_export', $schema);
+  return t('{domain_export} table created.');
+}
+
+/**
+ * Rebuild the {domain} table.
+ */
+function domain_update_7305(&$sandbox) {
+  // Reset the domain_id field as a plain integer.
+  db_drop_primary_key('domain');
+  db_drop_index('domain', 'domain_id');
+  $spec = array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0, 'description' => 'Domain numeric id.');
+  db_change_field('domain', 'domain_id', 'domain_id', $spec);
+  db_add_index('domain', 'domain_id', array('domain_id'));
+
+  // Add the machine name column.
+  if (!db_field_exists('domain', 'machine_name')) {
+    $spec = array('type' => 'varchar', 'length' => '40', 'not null' => TRUE, 'default' => '', 'description' => 'The machine name for this domain.');
+    db_add_field('domain', 'machine_name', $spec);
+  }
+  return t('{domain} table updated.');
+}
+
+/**
+ * Insert existing domain records into {domain_export} and {domain}.
+ */
+function domain_update_7306(&$sandbox) {
+  $domains = db_query("SELECT domain_id, subdomain FROM {domain} ORDER BY domain_id")->fetchAll();
+  foreach ($domains as $domain) {
+    $query = db_insert('domain_export')
+      ->fields(array(
+        'domain_id' => $domain->domain_id,
+        'machine_name' => md5($domain->subdomain),
+        'status' => 0,
+      ));
+    $query->execute();
+    $query = db_update('domain')
+      ->condition('domain_id', $domain->domain_id)
+      ->fields(array(
+        'machine_name' => md5($domain->subdomain),
+      ));
+    $query->execute();
+  }
+  // Now we can safely add the new primary key.
+  db_add_primary_key('domain', array('machine_name'));
+
+  return t('{domain_export} table populated.');
+}
diff --git a/domain.module b/domain.module
index a9f6444..4038e63 100644
--- a/domain.module
+++ b/domain.module
@@ -36,6 +36,12 @@ define('DOMAIN_ASSIGN_USERS', TRUE);
 define('DOMAIN_LIST_SIZE', 25);
 
 /**
+ * Defines the export statuses for a domain.
+ */
+define('DOMAIN_EXPORT_STATUS_DATABASE', 0);
+define('DOMAIN_EXPORT_STATUS_CODE', 1);
+
+/**
  * Module setup tasks.
  *
  * 1. Adds the domain user data to the $user object.
@@ -276,6 +282,19 @@ function domain_menu() {
     'file' => 'domain.admin.inc',
     'weight' => 50,
   );
+  if (module_exists('ctools')) {
+    $items['admin/structure/domain/export'] = array(
+      'title' => 'Export',
+      'access arguments' => array('administer domains'),
+      'page callback' => 'ctools_export_ui_switcher_page',
+      'page arguments' => array('domain', 'list'),
+      'description' => 'Edit domain record.',
+      'file' => 'export-ui.inc',
+      'file path' => drupal_get_path('module', 'ctools') . '/includes/',
+      'type' => MENU_LOCAL_TASK,
+      'weight' => 20,
+    );
+  }
   return $items;
 }
 
@@ -900,6 +919,10 @@ function domain_load($domain_id = NULL) {
  *   $domain array on success or -1 on failure.
  */
 function domain_save($values, $form_values = array()) {
+  // Exportables might pass an object.
+  if (is_object($values)) {
+    $values = (array) $values;
+  }
   // Must this be the default domain?
   // Used in cases where there are no domains present.
   $count = (bool) db_query("SELECT COUNT(domain_id) FROM {domain} WHERE is_default = 1")->fetchField();
@@ -911,9 +934,30 @@ function domain_save($values, $form_values = array()) {
 
   if (!empty($update)) {
     $action = 'domain_update';
+    $current = db_query("SELECT * FROM {domain} WHERE domain_id = :domain_id", array(':domain_id' => $values['domain_id']))->fetchAssoc();
+    // Cannot compare is_default right now.
+    // TODO: default handling from this function.
+    unset($current['is_default']);
+    $test = array_diff($current, $values);
+    if (!empty($test)) {
+      db_update('domain_export')
+        ->fields(array(
+          'status' => DOMAIN_EXPORT_STATUS_DATABASE,
+        ))
+        ->condition('domain_id', $values['domain_id'])
+        ->execute();
+    }
   }
   else {
     $action = 'domain_insert';
+    // Create a new record for possible exports.
+    $new_record = array(
+      'machine_name' => md5($values['subdomain']),
+      'status' => DOMAIN_EXPORT_STATUS_DATABASE,
+    );
+    drupal_write_record('domain_export', $new_record);
+    $values['domain_id'] = $new_record['domain_id'];
+    $values['machine_name'] = $new_record['machine_name'];
   }
 
   // If this is the default domain, reset other domains.
@@ -942,12 +986,19 @@ function domain_save($values, $form_values = array()) {
  *   An array of values passed by a form submit, if any.
  */
 function domain_delete($domain, $values = array()) {
+  // Exportables might pass an object.
+  if (is_object($domain)) {
+    $domain = (array) $domain;
+  }
+  // Let other modules act.
+  module_invoke_all('domain_delete', $domain, $values);
   // Delete the record.
   db_delete('domain')
     ->condition('domain_id', $domain['domain_id'])
     ->execute();
-  // Let other modules act.
-  module_invoke_all('domain_delete', $domain, $values);
+  db_delete('domain_export')
+    ->condition('domain_id', $domain['domain_id'])
+    ->execute();
   // Notify that node access needs to be rebuilt.
   node_access_needs_rebuild(TRUE);
 }
@@ -981,7 +1032,7 @@ function domain_lookup($domain_id = NULL, $subdomain = NULL, $reset = FALSE) {
   }
   // Get the data from the database. Doing this prevents extra queries.
   if (!isset($result) || $reset) {
-    $result = db_query("SELECT domain_id, subdomain, sitename, scheme, valid, weight, is_default FROM {domain}", array(), array('fetch' => PDO::FETCH_ASSOC))->fetchAllAssoc('domain_id');
+    $result = db_query("SELECT domain_id, subdomain, sitename, scheme, valid, weight, is_default, machine_name FROM {domain}", array(), array('fetch' => PDO::FETCH_ASSOC))->fetchAllAssoc('domain_id');
   }
   // If both are NULL, no lookup can be run.
   if ((is_null($domain_id) && is_null($subdomain)) || $domain_id < 0) {
@@ -1035,7 +1086,7 @@ function domain_lookup($domain_id = NULL, $subdomain = NULL, $reset = FALSE) {
 function domain_default($reset = FALSE, $alter = TRUE) {
   $default = &drupal_static(__FUNCTION__);
   if (empty($default) || $reset) {
-    $default = db_query("SELECT domain_id, subdomain, sitename, scheme, valid, weight, is_default FROM {domain} WHERE is_default = 1")->fetchAssoc();
+    $default = db_query("SELECT domain_id, subdomain, sitename, scheme, valid, weight, is_default, machine_name FROM {domain} WHERE is_default = 1")->fetchAssoc();
     // Let submodules overwrite the defaults, if they wish.
     if (empty($default)) {
       $default = array(
@@ -1044,7 +1095,8 @@ function domain_default($reset = FALSE, $alter = TRUE) {
         'sitename' => variable_get('site_name', 'Drupal'),
         'scheme' => empty($_SERVER['HTTPS']) ? 'http' : 'https',
         'valid' => 1,
-        'is_default' => 1
+        'is_default' => 1,
+        'machine_name' => md5($default['subdomain']),
       );
     }
     if ($alter) {
@@ -1090,14 +1142,23 @@ function domain_set_primary_domain() {
   }
   $check = (bool) db_query("SELECT COUNT(domain_id) FROM {domain} WHERE is_default = 1")->fetchField();
   if (empty($check)) {
+    // Create a new record for possible exports.
+    $new_record = array(
+      'machine_name' => md5($root),
+      'status' => DOMAIN_EXPORT_STATUS_DATABASE,
+    );
+    drupal_write_record('domain_export', $new_record);
+    // Write this record to the db.
     db_insert('domain')
       ->fields(array(
+          'domain_id' => $new_record['domain_id'],
           'subdomain' => $root,
           'sitename' => $site,
           'scheme' => $scheme,
           'weight' => -1,
           'valid' => 1,
           'is_default' => 1,
+          'machine_name' => md5($root),
       ))
       ->execute();
     // Allow other modules to respond to changes.
@@ -2991,3 +3052,12 @@ function domain_check_response($domain, $drush = FALSE) {
   }
   return FALSE;
 }
+
+/**
+ * Implements hook_ctools_plugin_directory.
+ */
+function domain_ctools_plugin_directory($module, $plugin) {
+  if ($module == 'ctools' && $plugin == 'export_ui') {
+    return 'plugins/' . $plugin;
+  }
+}
diff --git a/plugins/export_ui/domain.inc b/plugins/export_ui/domain.inc
index e69de29..0598d23 100644
--- a/plugins/export_ui/domain.inc
+++ b/plugins/export_ui/domain.inc
@@ -0,0 +1,16 @@
+<?php
+
+$plugin = array(
+  'schema' => 'domain',
+  'access' => 'administer domains',
+  'menu' => array(
+    'menu item' => 'domain/export',
+    'menu title' => 'Export',
+    'menu description' => 'Import and export domain settings.',
+  ),
+  'title singular' => t('domain'),
+  'title singular proper' => t('Domain'),
+  'title plural' => t('domains'),
+  'title plural proper' => t('Domains'),
+);
+
diff --git a/tests/domain.test b/tests/domain.test
index 21e8794..d4ab935 100644
--- a/tests/domain.test
+++ b/tests/domain.test
@@ -25,8 +25,10 @@ class DomainTestCase extends DrupalWebTestCase {
     if (empty($_SERVER['HTTP_HOST']) || $_SERVER['HTTP_HOST'] == 'default') {
       $_SERVER['HTTP_HOST'] = 'example.com';
     }
-    // Build teh {domain} table for this test run.
+    // Build the {domain} tables for this test run.
     db_query("TRUNCATE {domain}");
+    // TODO: Tests for domain exports.
+    db_query("TRUNCATE {domain_export}");
     domain_set_primary_domain();
     db_query("UPDATE {domain} SET sitename = 'TestDomainSitename' WHERE is_default = 1");
 
@@ -129,8 +131,18 @@ class DomainInstallTest extends DomainTestCase {
 
   // If the default domain is not in the database, the sitename will be default sitename.
   public function testDomainInstall() {
-    $domain = db_query("SELECT sitename FROM {domain} WHERE is_default = 1")->fetch();
-    $this->assertTrue($domain->sitename == 'TestDomainSitename', t('Default domain created successfully'));
+    $domain = domain_default(TRUE, FALSE);
+    $this->assertTrue($domain['sitename'] == 'TestDomainSitename', t('Default domain created successfully'));
+    $records = db_query("SELECT COUNT(domain_id) FROM {domain_export}")->fetchField();
+    $this->assertTrue($records == 1, t('{domain_export} has one record.'));
+    $domains = db_query("SELECT COUNT(domain_id) FROM {domain}")->fetchField();
+    $this->assertTrue($domains == 1, t('{domain} has one record.'));
+    $join = db_query("SELECT COUNT(d.domain_id) FROM {domain} d INNER JOIN {domain_export} de ON d.domain_id = de.domain_id")->fetchField();
+    $this->assertTrue($join == 1, t('Database counts match.'));
+    $join2 = db_query("SELECT COUNT(d.domain_id) FROM {domain} d INNER JOIN {domain_export} de ON d.domain_id = de.domain_id WHERE d.domain_id = 1")->fetchField();
+    $this->assertTrue($join2 == 1, t('Database records match.'));
+    $join = db_query("SELECT COUNT(d.domain_id) FROM {domain} d INNER JOIN {domain_export} de ON d.machine_name = de.machine_name")->fetchField();
+    $this->assertTrue($join == 1, t('Machine names match.'));
   }
 
   // Check the existence of our default grant.
@@ -395,6 +407,7 @@ class DomainUnitTest extends DomainTestCase {
     $nodes = node_load_multiple($node_ids);
     // Check domains.
     $set = TRUE;
+    $result = db_query("SELECT * FROM {domain_export}")->fetchAll();
     // TODO: This could be more elegant.
     foreach ($nodes as $node) {
       if (!isset($node->domains)) {
