diff --git a/src/Event/DefaultContentEvents.php b/src/Event/DefaultContentEvents.php
index 1dc78e5..5d7b391 100644
--- a/src/Event/DefaultContentEvents.php
+++ b/src/Event/DefaultContentEvents.php
@@ -6,12 +6,13 @@ namespace Drupal\default_content\Event;
  * Defines the events for Default Content.
  *
  * @see \Drupal\default_content\Event\ImportEvent
+ * @see \Drupal\default_content\Event\UpdateEvent
  * @see \Drupal\default_content\Event\ExportEvent
  */
 final class DefaultContentEvents {
 
   /**
-   * Name of the event fired when importing default content.
+   * Name of the event fired when importing new default content.
    *
    * This event allows modules to perform actions after the default content has
    * been imported. The event listener receives a
@@ -25,6 +26,21 @@ final class DefaultContentEvents {
    */
   const IMPORT = 'default_content.import';
 
+  /**
+   * Name of the event fired when updating existing default content.
+   *
+   * This event allows modules to perform actions after the default content has
+   * been updated. The event listener receives a
+   * \Drupal\default_content\Event\ImportEvent instance.
+   *
+   * @Event
+   *
+   * @see \Drupal\default_content\Event\UpdateEvent
+   *
+   * @var string
+   */
+  const UPDATE = 'default_content.update';
+
   /**
    * Name of the event fired when exporting default content.
    *
diff --git a/src/Event/UpdateEvent.php b/src/Event/UpdateEvent.php
new file mode 100644
index 0000000..f8ea75e
--- /dev/null
+++ b/src/Event/UpdateEvent.php
@@ -0,0 +1,61 @@
+<?php
+
+namespace Drupal\default_content\Event;
+
+use Symfony\Component\EventDispatcher\Event;
+
+/**
+ * Defines event fired when content is updated.
+ *
+ * @see \Drupal\default_content\Event\DefaultContentEvents
+ */
+class UpdateEvent extends Event {
+
+  /**
+   * An array of content entities that were updated.
+   *
+   * @var \Drupal\Core\Entity\ContentEntityInterface[]
+   */
+  protected $entities;
+
+  /**
+   * The module that provides the default content.
+   *
+   * @var string
+   */
+  protected $module;
+
+  /**
+   * Constructs a new update event.
+   *
+   * @param \Drupal\Core\Entity\ContentEntityInterface[] $entities
+   *   An array of content entities that were updated.
+   * @param string $module
+   *   The module that provided the default content.
+   */
+  public function __construct(array $entities, $module) {
+    $this->entities = $entities;
+    $this->module = $module;
+  }
+
+  /**
+   * Get the updated entities.
+   *
+   * @return \Drupal\Core\Entity\ContentEntityInterface[]
+   *   An array of content entities that were imported.
+   */
+  public function getUpdatedEntities() {
+    return $this->entities;
+  }
+
+  /**
+   * Gets the module name.
+   *
+   * @return string
+   *   The module name that provided the default content.
+   */
+  public function getModule() {
+    return $this->module;
+  }
+
+}
diff --git a/src/Importer.php b/src/Importer.php
index 600ed5c..fb86bde 100644
--- a/src/Importer.php
+++ b/src/Importer.php
@@ -4,7 +4,9 @@ namespace Drupal\default_content;
 
 use Drupal\Component\Graph\Graph;
 use Drupal\Core\Config\Entity\ConfigEntityInterface;
+use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Entity\RevisionableInterface;
 use Drupal\Core\Session\AccountSwitcherInterface;
 use Drupal\default_content\Event\DefaultContentEvents;
 use Drupal\default_content\Event\ImportEvent;
@@ -114,15 +116,17 @@ class Importer implements ImporterInterface {
   /**
    * {@inheritdoc}
    */
-  public function importContent($module) {
+  public function importContent($module, $update_existing = FALSE) {
     $created = [];
+    $updated = [];
     $folder = drupal_get_path('module', $module) . "/content";
 
     if (file_exists($folder)) {
       $root_user = $this->entityTypeManager->getStorage('user')->load(1);
       $this->accountSwitcher->switchTo($root_user);
       $file_map = [];
-      foreach ($this->entityTypeManager->getDefinitions() as $entity_type_id => $entity_type) {
+      $definitions = $this->entityTypeManager->getDefinitions();
+      foreach ($definitions as $entity_type_id => $entity_type) {
         $reflection = new \ReflectionClass($entity_type->getClass());
         // We are only interested in importing content entities.
         if ($reflection->implementsInterface(ConfigEntityInterface::class)) {
@@ -178,19 +182,58 @@ class Importer implements ImporterInterface {
         if (!empty($file_map[$link])) {
           $file = $file_map[$link];
           $entity_type_id = $file->entity_type_id;
-          $class = $this->entityTypeManager->getDefinition($entity_type_id)->getClass();
+          /* @var $entity_type \Drupal\Core\Entity\EntityTypeInterface */
+          $entity_type = $definitions[$entity_type_id];
           $contents = $this->parseFile($file);
-          $entity = $this->serializer->deserialize($contents, $class, 'hal_json', ['request_method' => 'POST']);
-          $entity->enforceIsNew(TRUE);
+
+          /* @var $entity \Drupal\Core\Entity\EntityInterface */
+          $entity = $this->serializer->deserialize($contents, $entity_type->getClass(), 'hal_json', ['request_method' => 'POST']);
+
+          $is_new = TRUE;
+
+          $old_entity = $this->lookupEntity($entity, $entity_type);
+
+          if ($old_entity && $update_existing) {
+            // All unique keys need to match the old entity.
+            $entity->{$entity_type->getKey('uuid')} = $old_entity->uuid();
+            $entity->{$entity_type->getKey('id')} = $old_entity->id();
+            $is_new = FALSE;
+            if ($this->isRevisionableEntity($entity)) {
+              $entity->{$entity_type->getKey('revision')} = $old_entity->getRevisionId();
+            }
+          }
+          elseif (!$old_entity) {
+            // Never import site level IDs.
+            $entity->{$entity_type->getKey('id')} = NULL;
+            $entity->{$entity_type->getKey('revision')} = NULL;
+          }
+
+          !$is_new && $old_entity ? $entity->setOriginalId($old_entity->id()) : $entity->enforceIsNew($is_new);
+          if ($this->isRevisionableEntity($entity)) {
+            $entity->setNewRevision($is_new);
+          }
+
           // Ensure that the entity is not owned by the anonymous user.
           if ($entity instanceof EntityOwnerInterface && empty($entity->getOwnerId())) {
             $entity->setOwner($root_user);
           }
-          $entity->save();
-          $created[$entity->uuid()] = $entity;
+
+          if ($old_entity && $update_existing) {
+            $updated[$entity->uuid()] = $entity;
+            $entity->save();
+          }
+          elseif (!$old_entity) {
+            $created[$entity->uuid()] = $entity;
+            $entity->save();
+          }
         }
       }
-      $this->eventDispatcher->dispatch(DefaultContentEvents::IMPORT, new ImportEvent($created, $module));
+      if (!empty($created)) {
+        $this->eventDispatcher->dispatch(DefaultContentEvents::IMPORT, new ImportEvent($created, $module));
+      }
+      if (!empty($updated)) {
+        $this->eventDispatcher->dispatch(DefaultContentEvents::UPDATE, new ImportEvent($updated, $module));
+      }
       $this->accountSwitcher->switchBack();
     }
     // Reset the tree.
@@ -200,6 +243,41 @@ class Importer implements ImporterInterface {
     return $created;
   }
 
+  /**
+   * Lookup whether an entity already exists.
+   *
+   * For most typical entities this is done by uuid.
+   * For core user 1 this is done by id.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity that will be imported.
+   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
+   *   The entity type for this entity.
+   *
+   * @return \Drupal\Core\Entity\EntityInterface|NULL
+   *   The old entity, or NULL if no entity.
+   */
+  public function lookupEntity($entity, $entity_type) {
+    $entity_storage = $this->entityTypeManager->getStorage($entity_type->id());
+
+    $lookup_properties = [$entity_type->getKey('uuid') => $entity->uuid()];
+    // Alter the lookup properties for known core irregularities.
+    if ($entity_type->id() === 'user' && $entity->id() == 1) {
+      $lookup_properties = [$entity_type->getKey('id') => $entity->id()];
+    }
+
+    $entity_query = $entity_storage->getQuery()->accessCheck(FALSE);
+    foreach ($lookup_properties as $key => $value) {
+      // Cast scalars to array so we can consistently use an IN condition.
+      $entity_query->condition($key, (array) $value, 'IN');
+    }
+    $result = $entity_query->execute();
+
+    $old_entity = $result ? $entity_storage->load(current($result)) : [];
+
+    return $old_entity;
+  }
+
   /**
    * Parses content files.
    *
@@ -255,4 +333,17 @@ class Importer implements ImporterInterface {
     return $this->vertexes[$item_link];
   }
 
+  /**
+   * Checks a given entity for revision support.
+   *
+   * @param EntityInterface $entity
+   *   A typical drupal entity object.
+   *
+   * @return bool
+   *   Whether this entity supports revisions.
+   */
+  protected function isRevisionableEntity(EntityInterface $entity) {
+    return $entity instanceof RevisionableInterface && $entity->getEntityType()->isRevisionable();
+  }
+
 }
diff --git a/src/ImporterInterface.php b/src/ImporterInterface.php
index 0d300a3..235184b 100644
--- a/src/ImporterInterface.php
+++ b/src/ImporterInterface.php
@@ -12,10 +12,12 @@ interface ImporterInterface {
    *
    * @param string $module
    *   The module to create the default content from.
+   * @param bool $update_existing
+   *   Whether to update existing entities or ignore them.
    *
    * @return \Drupal\Core\Entity\EntityInterface[]
    *   An array of created entities keyed by their UUIDs.
    */
-  public function importContent($module);
+  public function importContent($module, $update_existing = FALSE);
 
 }
diff --git a/tests/src/Functional/DefaultContentTest.php b/tests/src/Functional/DefaultContentTest.php
index c6807a4..777cf59 100644
--- a/tests/src/Functional/DefaultContentTest.php
+++ b/tests/src/Functional/DefaultContentTest.php
@@ -102,4 +102,34 @@ class DefaultContentTest extends BrowserTestBase {
     $this->assertTrue(!empty($term_id), 'Term reference populated');
   }
 
+  /**
+   * Test re-importing default content.
+   */
+  public function testReImport() {
+    // Login as admin.
+    $this->drupalLogin($this->drupalCreateUser(array_keys(\Drupal::moduleHandler()->invokeAll(('permission')))));
+
+      // Enable the module and import the content.
+    \Drupal::service('module_installer')->install(['default_content_test'], TRUE);
+    $this->rebuildContainer();
+    $original_nodes = \Drupal::entityTypeManager()->getListBuilder('node')->getStorage()->loadByProperties(['type' => 'page']);
+
+    // Change the node content.
+    $node = $this->getNodeByTitle('Imported node');
+    $node->title = 'Updated node';
+    $node->save();
+
+      // Re-import the content and check there are no changes.
+    \Drupal::service('default_content.importer')->importContent('default_content_test');
+    $new_nodes = \Drupal::entityTypeManager()->getListBuilder('node')->getStorage()->loadByProperties(['type' => 'page']);
+    $this->assertSame(array_keys($new_nodes), array_keys($original_nodes), 'No new content has been imported.');
+    $node = $this->getNodeByTitle('Imported node');
+    $this->assertEmpty($node, "Imported content has not been updated.");
+
+    // Re-import the content and check the content has been updated.
+    \Drupal::service('default_content.importer')->importContent('default_content_test', TRUE);
+    $node = $this->getNodeByTitle('Imported node');
+    $this->assertNotEmpty($node, "Imported content has been updated.");
+  }
+
 }
