diff --git filefield_paths.crud.inc filefield_paths.crud.inc
new file mode 100644
index 0000000..5d7351e
--- /dev/null
+++ filefield_paths.crud.inc
@@ -0,0 +1,127 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ *   CRUD functions for Filefield Paths.
+ */
+
+/**
+ * Create/Update a record.
+ *
+ * @param $record
+ *   The object to be saved. If record_id is null, a new record will be inserted,
+ *   otherwise the existing record will be updated.
+ * @return
+ *   The saved record, including the record_id for new records.
+ */
+function filefield_paths_save_record(&$record) {
+  if (empty($record->name)) {
+    $record->name = _filefield_paths_record_name($record->type, $record->field);
+  }
+  $update = (isset($record->record_id) && is_numeric($record->record_id)) ? array('record_id') : array();
+  return drupal_write_record('filefield_paths', $record, $update);
+}
+
+/**
+ * Load a record based on Node type and field name.
+ *
+ * @param $type_name
+ *   String node type name.
+ * @param $field_name
+ *   String field name.
+ * @return
+ *   The record object.
+ */
+function filefield_paths_load_record($type_name, $field_name) {
+  $name = _filefield_paths_record_name($type_name, $field_name);
+
+  return filefield_paths_load_record_by_name($name);
+}
+
+/**
+ * Load a record by a machine name.
+ *
+ * @param $name
+ *   The machine name for this record. Typically this is a node type name and 
+ *   field name delimited with a hyphen, e.g. TYPE-FIELD.
+ * @return
+ *   The record object.
+ */
+function filefield_paths_load_record_by_name($name) {
+  if (function_exists('ctools_include')) {
+    ctools_include('export');
+    $result = ctools_export_load_object('filefield_paths', 'names', array($name));
+  }
+  else {
+    static $result;
+
+    if (empty($result[$name])) {
+      $record = db_fetch_object(db_query("SELECT * FROM {filefield_paths} WHERE name = '%s'", $name));
+
+      $result[$name] = filefield_paths_unserialize_record($record);
+    }
+  }
+
+  if (isset($result[$name])) {
+    return $result[$name];
+  }
+}
+
+/**
+ * Helper function to unserialize any columns in a filefield_path record.
+ *
+ * @param $record
+ *   The filefield_path object that has been fetched from the database.
+ * @return
+ *   The filefield_path object, with unserialized data.
+ */
+function filefield_paths_unserialize_record(&$record) {
+  $schema = drupal_get_schema('filefield_paths');
+
+  // Unserialize any columns if necessary. @see _ctools_export_unpack_object()
+  foreach ($schema['fields'] as $field => $info) {
+    $record->$field = empty($info['serialize']) ? $record->$field : unserialize(db_decode_blob($record->$field));
+  }
+
+  return $record;
+}
+
+/**
+ * Load all records.
+ *
+ * @return
+ *   An array of records, keyed by their machine name.
+ */
+function filefield_paths_load_all_records() {
+  if (function_exists('ctools_include')) {
+    ctools_include('export');
+    $records = ctools_export_load_object('filefield_paths', 'all');
+  }
+  else {
+    static $records;
+
+    if (empty($records)) {
+      $result = db_query("SELECT * FROM {filefield_paths}");
+
+      while ($record = db_fetch_object($result)) {
+        $records[$record->name] = filefield_paths_unserialize_record($record);
+      }
+    }
+  }
+
+  return $records;
+}
+
+/**
+ * Delete a record.
+ *
+ * @param $type_name
+ *   String node type name.
+ * @param $field_name
+ *   String field name.
+ */
+function filefield_paths_delete_record($type_name, $field_name) {
+  $sql = "DELETE FROM {filefield_paths} WHERE type = '%s' AND field = '%s'";
+  return db_query($sql, $type_name, $field_name);
+}
diff --git filefield_paths.install filefield_paths.install
index 89bef05..7e20ea7 100644
--- filefield_paths.install
+++ filefield_paths.install
@@ -10,13 +10,41 @@
  */
 function filefield_paths_schema() {
   $schema['filefield_paths'] = array(
+    'export' => array(
+      'key' => 'name',
+      'identifier' => 'filefield_paths',
+      'default hook' => 'filefield_paths_defaults',  // Function hook name.
+      'status' => 'filefield_paths_status',
+      'api' => array(
+        'owner' => 'filefield_paths',
+        'api' => 'filefield_paths',  // Base name for api include files.
+        'minimum_version' => 1,
+        'current_version' => 1,
+      ),
+    ),
     'fields' => array(
+      'record_id' => array(
+        'type' => 'serial',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'description' => 'Primary ID field for the table. Not used for anything except internal lookups.',
+        'no export' => TRUE, // Do not export database-only keys.
+      ),
+      'name' => array(
+        'description' => 'The machine name for this record. Typically this is a node type name and field name delimited with a hyphen, e.g. TYPE-FIELD.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
       'type' => array('type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'default' => ''),
       'field' => array('type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'default' => ''),
       'filename' => array('type' => 'text', 'size' => 'medium', 'not null' => TRUE, 'serialize' => TRUE),
       'filepath' => array('type' => 'text', 'size' => 'medium', 'not null' => TRUE, 'serialize' => TRUE),
     ),
+    'primary key' => array('record_id'),
     'unique keys' => array(
+      'name' => array('name'),
       'type_field' => array('type', 'field'),
     ),
   );
@@ -144,7 +172,7 @@ function filefield_paths_update_6100() {
     }
   }
 
-  $ret[] = update_sql("DELETE FROM {variable} WHERE name LIKE 'filefield_paths_%'");
+  $ret[] = update_sql("DELIMITER FROM {variable} WHERE name LIKE 'filefield_paths_%'");
   cache_clear_all('variables', 'cache');
 
   return $ret;
@@ -195,3 +223,50 @@ function filefield_paths_update_6103() {
 
   return array();
 }
+
+/**
+ * Change to using a single key field for identifying filefield_paths. This aids 
+ * in adding support for exportability.
+ */
+function filefield_paths_update_6104() {
+  $ret = array();
+
+  // Add our new serial primary key column.
+  $field = array(
+    'type' => 'serial',
+    'unsigned' => TRUE,
+    'not null' => TRUE,
+    'description' => 'Primary ID field for the table. Not used for anything except internal lookups.',
+  );
+
+  $new_keys = array('primary key' => array('record_id'));
+
+  db_add_field($ret, 'filefield_paths', 'record_id', $field, $new_keys);
+
+  // Add our new name column.
+  $field = array(
+    'description' => 'The machine name for this record. Typically this is a node type name and field name delimited with a hyphen, e.g. TYPE-FIELD.',
+    'type' => 'varchar',
+    'length' => 255,
+    'not null' => TRUE,
+    'default' => '',
+  );
+
+  $new_keys = array('unique keys' => array('name' => array('name')));
+
+  db_add_field($ret, 'filefield_paths', 'name', $field, $new_keys);
+
+  // Update existing rows with a machine name.
+  global $db_type;
+
+  if ($db_type == 'mysql' || $db_type == 'mysqli') {
+    $sql = "UPDATE {filefield_paths} SET name = CONCAT(type, '". FILEFIELD_PATHS_DELIMITER ."', field)";
+  }
+  else {
+    $sql = "UPDATE {filefield_paths} SET name = type||'". FILEFIELD_PATHS_DELIMITER ."'||field";
+  }
+
+  $ret[] = update_sql($sql);
+
+  return $ret;
+}
\ No newline at end of file
diff --git filefield_paths.module filefield_paths.module
index 91182bd..e44409b 100644
--- filefield_paths.module
+++ filefield_paths.module
@@ -5,6 +5,10 @@
  * Contains core functions for the FileField Paths module.
  */
 
+define('FILEFIELD_PATHS_DELIMITER', '-');
+
+module_load_include('inc', 'filefield_paths', 'filefield_paths.crud');
+
 /**
  * Implements hook_filefield_paths_field_settings().
  */
@@ -96,23 +100,22 @@ function filefield_paths_form_alter(&$form, $form_state, $form_id) {
 
   // If supporting module enabled, show FileField Paths settings form.
   if (count($ffp) > 0) {
-    $fields = module_invoke_all('filefield_paths_field_settings');
-    foreach ($ffp as $field_name => $field_data) {
+    $form['#ffp_fields'] = module_invoke_all('filefield_paths_field_settings');
 
-      $result = db_fetch_object(
-        db_query("SELECT * FROM {filefield_paths} WHERE type = '%s' AND field = '%s'", $field_data['type'], $field_name)
-      );
-      if (!empty($result)) {
-        foreach ($fields as &$field) {
-          $field['settings'] = unserialize($result->$field['sql']);
-        }
-        unset($field);
-      }
+    foreach ($ffp as $field_name => $field_data) {
+      $record = filefield_paths_load_record($field_data['type'], $field_name);
 
       $count = 0;
-      foreach ($fields as $name => $field) {
+      foreach ($form['#ffp_fields'] as $name => $field) {
         $count++;
 
+        if ($record) {
+          $column = $field['sql'];
+          $field['settings'] = $record->$column;
+          // Update the $form array as well.
+          $form['#ffp_fields'][$name] = $field;
+        }
+
         if (isset($field['form']) && is_array($field['form'])) {
           $keys = array_keys($field['form']);
           for ($i = 1; $i < count($field['form']); $i++) {
@@ -235,6 +238,7 @@ function filefield_paths_form_alter(&$form, $form_state, $form_id) {
  * Implements hook_form_submit().
  */
 function filefield_paths_form_submit($form, &$form_state) {
+  $values = $form_state['values'];
   $ffp = array();
 
   // Invoke hook_filefield_paths_form_submit().
@@ -245,64 +249,45 @@ function filefield_paths_form_submit($form, &$form_state) {
 
   if (count($ffp) > 0) {
     $retroactive_update = FALSE;
-    $fields = module_invoke_all('filefield_paths_field_settings');
+    $fields = $form['#ffp_fields'];
     foreach ($ffp as $field_name => $field_data) {
-      $cols = $vals = $data = array();
+      $record = filefield_paths_load_record($field_data['type'], $field_name);
 
+      if (empty($record)) {
+        $record = new stdClass();
+        $record->type = $field_data['type'];
+        $record->field = $field_name;
+      }
+
+      // Now add the other columns to the record.
       foreach ($fields as $name => &$field) {
         $field['settings'] = array(
-          'value' => $form_state['values']['ffp_' . $field_name][$name],
-          'tolower' => $form_state['values']['ffp_' . $field_name][$name . '_cleanup'][$name . '_tolower'],
-          'pathauto' => $form_state['values']['ffp_' . $field_name][$name . '_cleanup'][$name . '_pathauto'],
-          'transliterate' => $form_state['values']['ffp_' . $field_name][$name . '_cleanup'][$name . '_transliterate']
+          'value' => $values['ffp_' . $field_name][$name],
+          'tolower' => $values['ffp_' . $field_name][$name . '_cleanup'][$name . '_tolower'],
+          'pathauto' => $values['ffp_' . $field_name][$name . '_cleanup'][$name . '_pathauto'],
+          'transliterate' => $values['ffp_' . $field_name][$name . '_cleanup'][$name . '_transliterate']
         );
 
         // Store additional settings from addon modules.
         if (isset($field['data'])) {
           foreach ($field['data'] as $key => $value) {
-            $field['settings'][$key] = $form_state['values']['ffp_' . $field_name][$value];
+            $field['settings'][$key] = $values['ffp_' . $field_name][$value];
           }
         }
 
-        $cols[] = $field['sql'];
-        $vals[] = "'%s'";
-        $data[] = serialize($field['settings']);
+        $column = $field['sql'];
+        $record->$column = $field['settings'];
       }
 
-      $result = db_fetch_object(
-        db_query(
-          "SELECT * FROM {filefield_paths} WHERE type = '%s' AND field = '%s'",
-          $field_data['type'], $field_name
-        )
-      );
-
-      // Update existing entry.
-      if (!empty($result)) {
-        foreach ($cols as &$col) {
-          $col .= " = '%s'";
-        }
-
-        db_query(
-          "UPDATE {filefield_paths} SET " . implode(', ', $cols) . " WHERE type = '%s' AND field = '%s'",
-          array_merge($data, array($field_data['type'], $field_name))
-        );
-      }
+      filefield_paths_save_record($record);
 
-      // Create new entry.
-      else {
-        db_query(
-          "INSERT INTO {filefield_paths} (type, field, " . implode(', ', $cols) . ") VALUES ('%s', '%s', " . implode(', ', $vals) . ")",
-          array_merge(array($field_data['type'], $field_name), $data)
-        );
-      }
-
-      if ($form_state['values']['ffp_' . $field_name]['retroactive_update']) {
+      if ($values['ffp_' . $field_name]['retroactive_update']) {
         $retroactive_update = TRUE;
         $module = isset($form['#field']) ? $form['#field']['module'] : $field_name;
         filefield_paths_batch_update($module, $field_name, arg(3));
       }
 
-      variable_set("ffp_{$field_data['type']}_{$field_name}", $form_state['values']['ffp_' . $field_name]['active_updating']);
+      variable_set("ffp_{$field_data['type']}_{$field_name}", $values['ffp_' . $field_name]['active_updating']);
     }
 
     if ($retroactive_update) {
@@ -465,10 +450,7 @@ function filefield_paths_node_update(&$node) {
 function filefield_paths_content_fieldapi($op, $field) {
   switch ($op) {
     case 'delete instance':
-      db_query(
-        "DELETE FROM {filefield_paths} WHERE type = '%s' AND field = '%s'",
-        $field['type_name'], $field['field_name']
-      );
+      filefield_paths_delete_record($field['type_name'], $field['field_name']);
       break;
   }
 }
@@ -500,13 +482,12 @@ function filefield_paths_get_fields(&$node, $op = NULL) {
 
   // Load fields settings
   foreach ($ffp['#types'] as $name => $temp) {
-    $result = db_fetch_object(
-      db_query("SELECT * FROM {filefield_paths} WHERE type = '%s' AND field = '%s'", $node->type, $name)
-    );
+    $record = filefield_paths_load_record($node->type, $name);
 
-    if (!empty($result)) {
+    if (!empty($record)) {
       foreach ($fields as $field) {
-        $ffp['#settings'][$name][$field['sql']] = unserialize($result->$field['sql']);
+        $column = $field['sql'];
+        $ffp['#settings'][$name][$column] = $record->$column;
       }
     }
   }
@@ -831,3 +812,31 @@ function _filefield_paths_check_directory(&$directory, $mode = 0, $form_item = N
 
   return TRUE;
 }
+
+/**
+ * Helper function to create a machine name from node type name and field name.
+ *
+ * @param $type_name
+ *   String node type name.
+ * @param $field_name
+ *   String field name.
+ * @return
+ *   The node type and field name delimited by FILEFIELD_PATHS_DELIMITER.
+ */
+function _filefield_paths_record_name($type_name, $field_name) {
+  return $type_name . FILEFIELD_PATHS_DELIMITER . $field_name;
+}
+
+/**
+ * Implementation of hook_features_pipe_COMPONENT_alter().
+ */
+function filefield_paths_features_pipe_content_alter(&$pipe, $data, $export, $module_name) {
+  // We need to verify that Ctools exists before we add anything to the pipe.
+  if (function_exists('ctools_include')) {
+    foreach ($data as $name) {
+      if ($record = filefield_paths_load_record_by_name($name)) {
+        $pipe['filefield_paths'][] = $name;
+      }
+    }
+  }
+}
\ No newline at end of file
