diff --git a/feeds.info b/feeds.info
index 83b0c46..5b80aaf 100644
--- a/feeds.info
+++ b/feeds.info
@@ -30,6 +30,7 @@ files[] = tests/feeds_date_time.test
 files[] = tests/feeds_mapper_date.test
 files[] = tests/feeds_mapper_field.test
 files[] = tests/feeds_mapper_file.test
+files[] = tests/feeds_mapper_node_reference.test
 files[] = tests/feeds_mapper.test
 files[] = tests/feeds_fetcher_file.test
 files[] = tests/feeds_processor_node.test
diff --git a/mappers/node_reference.inc b/mappers/node_reference.inc
new file mode 100644
index 0000000..92f2cfd
--- /dev/null
+++ b/mappers/node_reference.inc
@@ -0,0 +1,121 @@
+<?php
+
+/**
+ * @file
+ * Implementation of Feeds API for mapping node_reference.module fields (CCK).
+ */
+
+/**
+ * Implements hook_feeds_processor_targets_alter().
+ *
+ * @see FeedsNodeProcessor::getMappingTargets()
+ */
+function node_reference_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_name) {
+  foreach (field_info_instances($entity_type, $bundle_name) as $name => $instance) {
+    $info = field_info_field($name);
+    if ($info['type'] == 'node_reference') {
+      $targets[$name . ':title'] = array(
+        'name' => t('@label (by title)', array('@label' => $instance['label'])),
+        'callback' => 'node_reference_feeds_set_target',
+        'description' => t('The CCK node reference @label of the node, matched by node title.', array('@label' => $instance['label'])),
+        'real_target' => $name,
+      );
+      $targets[$name . ':nid'] = array(
+        'name' => t('@label (by nid)', array('@label' => $instance['label'])),
+        'callback' => 'node_reference_feeds_set_target',
+        'description' => t('The CCK node reference @label of the node, matched by node ID.', array('@label' => $instance['label'])),
+        'real_target' => $name,
+      );
+      $targets[$name . ':url'] = array(
+        'name' => t('@label (by Feeds URL)', array('@label' => $instance['label'])),
+        'callback' => 'node_reference_feeds_set_target',
+        'description' => t('The CCK node reference @label of the node, matched by Feeds URL.', array('@label' => $instance['label'])),
+        'real_target' => $name,
+      );
+      $targets[$name . ':guid'] = array(
+        'name' => t('@label (by Feeds GUID)', array('@label' => $instance['label'])),
+        'callback' => 'node_reference_feeds_set_target',
+        'description' => t('The CCK node reference @label of the node, matched by Feeds GUID.', array('@label' => $instance['label'])),
+        'real_target' => $name,
+      );
+    }
+  }
+}
+
+/**
+ * Implements hook_feeds_set_target().
+ *
+ * When the callback is invoked, $target contains the name of the field the
+ * user has decided to map to and $value contains the value of the feed item
+ * element the user has picked as a source.
+ *
+ * @param $source
+ *   A FeedsSource object.
+ * @param $entity
+ *   The entity to map to.
+ * @param $target
+ *   The target key on $entity to map to.
+ * @param $value
+ *   The value to map. MUST be an array.
+ */
+function node_reference_feeds_set_target($source, $entity, $target, $value) {
+  // Determine whether we are matching against title, nid, URL, or GUID.
+  list($target, $match_key) = explode(':', $target, 2);
+
+  // Load field definition.
+  $field_info = field_info_field($target);
+
+  // Allow for multiple-value fields.
+  $value = is_array($value) ? $value : array($value);
+
+  // Allow importing to the same target with multiple mappers.
+  $field = isset($entity->$target) ? $entity->$target : array();
+
+  // Match values against nodes and add to field.
+  foreach ($value as $v) {
+    $nids = array();
+    $v = trim($v);
+
+    switch ($match_key) {
+      case 'url':
+      case 'guid':
+        // Lookup node ID by Feeds unique value.
+        $result = db_query("SELECT nid FROM {feeds_node_item} WHERE %s = '%s'", $match_key, $v);
+        // Since GUID and URL are only guaranteed to be unique per feed,
+        // multiple nids from different feeds may result.
+        while ($row = db_fetch_array($result)) {
+          $nids[] = $row['nid'];
+        }
+        // Ensure nids are valid node ids for this field.
+        $nids = !empty($nids) ? array_keys(node_reference_potential_references($field_info, array('ids' => $nids))) : array();
+        break;
+
+      case 'title':
+        // Validate title.
+        if ((is_string($v) && $v !== '') || is_numeric($v)) {
+          // Lookup potential exact matches for the value.
+          $nids = array_keys(node_reference_potential_references($field_info, array('string' => $v, 'match' => 'equals')));
+        }
+        break;
+
+      case 'nid':
+        // Ensure nid is a valid node id for this field.
+        $nids = array_keys(node_reference_potential_references($field_info, array('ids' => array($v))));
+        break;
+    }
+
+    if (empty($nids)) {
+      // Alert if no matches were found.
+      drupal_set_message(t("'%value' does not match a valid node %key for the '%field' field.", array('%value' => $v, '%key' => $match_key, '%field' => $target)));
+    }
+    else {
+      // Add the reference (ignoring duplicates).
+      foreach ($nids as $nid) {
+        $field['und'][] = array('nid' => $nid);
+      }
+    }
+
+  }
+
+  $entity->{$target} = $field;
+}
diff --git a/tests/feeds/node_reference.csv b/tests/feeds/node_reference.csv
new file mode 100644
index 0000000..c336126
--- /dev/null
+++ b/tests/feeds/node_reference.csv
@@ -0,0 +1,4 @@
+title,ref
+title a,10
+title b,20
+title c,30
diff --git a/tests/feeds_mapper.test b/tests/feeds_mapper.test
index 78da637..37d117f 100644
--- a/tests/feeds_mapper.test
+++ b/tests/feeds_mapper.test
@@ -24,9 +24,9 @@ class FeedsMapperTestCase extends FeedsWebTestCase {
     'link_field' => 'link_field',
     'number_float' => 'number',
     'number_integer' => 'number',
-    'nodereference' => 'nodereference_select',
+    'node_reference' => 'options_select',
     'text' => 'text_textfield',
-    'userreference' => 'userreference_select',
+    'user_reference' => 'options_select',
    );
 
   /**
diff --git a/tests/feeds_mapper_node_reference.test b/tests/feeds_mapper_node_reference.test
new file mode 100644
index 0000000..98e8ccb
--- /dev/null
+++ b/tests/feeds_mapper_node_reference.test
@@ -0,0 +1,135 @@
+<?php
+
+/**
+ * @file
+ * Test case for CCK node reference mapper mappers/node_reference.inc.
+ */
+
+/**
+ * Class for testing Feeds <em>node reference</em> mapper.
+ */
+class FeedsMapperNodeReferenceTestCase extends FeedsMapperTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Mapper: Node Reference',
+      'description' => 'Test Feeds Mapper support for Node Reference CCK fields.',
+      'group' => 'Feeds',
+      'dependencies' => array('node_reference'),
+    );
+  }
+
+  /**
+   * Set up the test.
+   */
+  function setUp() {
+    parent::setUp(array('ctools', 'job_scheduler', 'feeds', 'feeds_ui', 'field', 'references', 'options', 'node_reference'));
+  }
+
+  /**
+   * Basic test loading an rss file.
+   */
+  function test() {
+
+    // Create content type.
+    $typename = $this->createContentType(array(), array(
+      'ref' => array(
+        'type' => 'node_reference',
+        // 'widget' => 'node_reference_autocomplete',
+        'settings' => array(
+          'field[settings][referenceable_types][page]' => 'page',
+        ),
+      ),
+    ));
+    $this->drupalPost(NULL, array( 'field[cardinality]' => -1 ), 'Save settings');
+
+    $rss = simplexml_load_file($this->absolutePath() . '/tests/feeds/developmentseed_changes.rss2');
+    $categories = $rss->xpath('//category');
+
+    foreach ($categories as &$category) {
+      $category = (string) $category;
+    }
+    $categories = array_unique($categories);
+    foreach ($categories as $category) {
+      $this->drupalPost('node/add/page', array('title' => $category), 'Save');
+    }
+
+    // Create and configure importer.
+    $this->createImporterConfiguration('Node Reference', 'ref_test_title');
+    $this->setSettings('ref_test_title', NULL, array('content_type' => '', 'import_period' => FEEDS_SCHEDULE_NEVER));
+    $this->setPlugin('ref_test_title', 'FeedsFileFetcher');
+    $this->setSettings('ref_test_title', 'FeedsFileFetcher', array('allowed_extensions' => 'rss2'));
+    $this->setSettings('ref_test_title', 'FeedsNodeProcessor', array('content_type' => $typename));
+    $this->addMappings('ref_test_title', array(
+      array(
+        'source' => 'title',
+        'target' => 'title',
+      ),
+      array(
+        'source' => 'tags',
+        'target' => 'field_ref:title',
+      ),
+    ));
+
+    // Import file.
+    $this->importFile('ref_test_title', $this->absolutePath() . '/tests/feeds/developmentseed_changes.rss2');
+    $this->assertText('10 imported items total.');
+
+    foreach ($rss->xpath('//item') as $item) {
+      $this->drupalGet('node/' . $this->findNodeByTitle($item->title));
+      foreach ($item->category as $category) {
+        $this->assertText((string) $category);
+      }
+    }
+
+    // Delete everything and start over for nid test
+    $this->drupalPost('import/ref_test_title/delete-items', array(), 'Delete');
+
+    // Create and configure importer.
+    $this->createImporterConfiguration('Node Reference', 'ref_test_nid');
+    $this->setSettings('ref_test_nid', NULL, array('content_type' => '', 'import_period' => FEEDS_SCHEDULE_NEVER));
+    $this->setPlugin('ref_test_nid', 'FeedsFileFetcher');
+    $this->setPlugin('ref_test_nid', 'FeedsCSVParser');
+    $this->setSettings('ref_test_nid', 'FeedsNodeProcessor', array('content_type' => $typename));
+    $this->addMappings('ref_test_nid', array(
+      array(
+        'source' => 'title',
+        'target' => 'title',
+      ),
+      array(
+        'source' => 'ref',
+        'target' => 'field_ref:nid',
+      ),
+    ));
+
+    // Import file.
+    $this->importFile('ref_test_nid', $this->absolutePath() . '/tests/feeds/node_reference.csv');
+    $this->assertText('3 imported items total.');
+    $this->drupalGet('node/' . $this->findNodeByTitle('title a'));
+    $this->assertText('custom mapping');
+    $this->drupalGet('node/' . $this->findNodeByTitle('title b'));
+    $this->assertText('MIX Market');
+    $this->drupalGet('node/' . $this->findNodeByTitle('title c'));
+    $this->assertText('usability');
+  }
+
+  /**
+   * Override parent::getFormFieldsNames().
+   */
+  protected function getFormFieldsNames($field_name, $index) {
+    return array("field_{$field_name}[{$index}][nid]");
+  }
+
+  /**
+   * Find a node by title and return the NID.
+   */
+  private function findNodeByTitle($title) {
+    //$nids = array_keys(node_load_multiple(NULL, array('title' => $item->title))); // DEPRECATED
+    $query = new EntityFieldQuery();
+    $entities = $query
+      ->entityCondition('entity_type', 'node')
+      ->propertyCondition('title', $title)
+      ->execute();
+    $nids = array_keys($entities['node']);
+    return $nids[0];
+  }
+}
