We're upgrading our site from D7 to D8, which has vocabulary containing multi-level parent-child hierarchy. The list is too long (around 5K-10K terms) to import manually.

We've tried using migrate in D8 Core and extending it using migrate_plus and migrate_tools module. These works really well when there is no term hierarchy.

How can we get it working for importing term with hierarchy. The value it accepts for parent is term id. If we pass the parent name (as we're importing it for first-time), it creates the term at root level. Are we missing anything? If we can not do this only with these modules, how can we extend these modules. References would also greatly appreciated.

  • 1
    Could be a bug because the migrate source plugin for taxonomy terms has code that explicitly looks up the taxonomy term parent. Edit: there's a test in core that says that it is in fact working - api.drupal.org/api/drupal/…
    – mradcliffe
    Commented Apr 4, 2016 at 15:05
  • It is working when passing the parent Term ID, but I want to make it work for import of parent as well as child import at same time. Thanks for sharing link, will check the link and see if I'm missing anything.
    – Yogesh
    Commented Apr 5, 2016 at 4:32
  • Related: How to migrate taxonomy with hierarchy?
    – kenorb
    Commented Aug 30, 2017 at 18:44

7 Answers 7


If you want to import Taxonomy with Hierarchy along with the existing tid then follow the following. Configure your import configuration some thing like this

id: taxonomy_migration
class: null
field_plugin_method: null
cck_plugin_method: null
 - CSV
migration_group: null
label: 'Taxonomy migration from CSV'
  plugin: csv
  path: test.csv //path of file
  header_row_count: 1
    - tid //unique key which is used for mapping while importing other content related with this taxonomy
  parent: //this is for your parent term id
    plugin: migration_lookup
    migration: taxonomy_migration //this is the current migration id which will help you to make parent child on taxonomy
    source: pid //parent id source from your csv file
  name: term
  tid: tid
  plugin: 'entity:taxonomy_term'
  default_bundle: test_taxonomy //your vocabulary machine name where you want to import 
migration_dependencies: null
migration_dependencies: null

now your csv file will be like this

enter image description here

now you can check your taxonomy, result will be like in the image below with existing tid.

enter image description here


It's a little late, but I think I just solved this...

In your migrate.whatever.yml file you have to add a process plugin in the parent source:

  plugin: entity:taxonomy_term

  vid: vocab
  name: name
  weight: weight
      plugin: migration
      migration: whatever // This should be the name of your current migration
      source: parent // This is the name of the source field
      no_stub: true
      plugin: default_value // Not required, but useful for large data sets
      default_value: 0
  • 1
    Late? It's only early afternoon over here ... Commented Feb 10, 2017 at 13:58
  • It works with me without 'no_stub: true' Commented Aug 30, 2020 at 15:01

Alternative solution to Migrate module is to use Term CSV Export Import module which supports import a list of terms with parent structure.

Example format of CSV file:


There is a module that can import hierarchical taxonomy terms with ease. Have a look at Drupal 8 version of module and its name is Hierarchical Taxonomy Importer.

This can import terms on nested levels from a CSV file. Here is the link of module.


There is no limitation for parent child relationship depth.


See this Patch: https://www.drupal.org/project/drupal/issues/2965938#comment-12587479

# This patch file was generated by NetBeans IDE
# It uses platform neutral UTF-8 encoding and \n newlines.
--- a/core/modules/migrate/src/MigrateExecutable.php
+++ b/core/modules/migrate/src/MigrateExecutable.php
@@ -363,8 +363,18 @@
           $break = FALSE;
           foreach ($value as $scalar_value) {
             try {
-              $new_value[] = $plugin->transform($scalar_value, $this, $row, $destination);
+//              $new_value[] = $plugin->transform($scalar_value, $this, $row, $destination);
+                // reserve salar value
+                            $result = $plugin->transform($scalar_value, $this, $row, $destination);
+                            // fix parent_id always return null on MigrationLookup::transform
+                            if (is_null($result)) {
+                                if ($scalar_value) {
+                                    $new_value[] = $scalar_value;
+                            } else {
+                                $new_value[] = $result;
+                            }
+            }
             catch (MigrateSkipProcessException $e) {
               $new_value[] = NULL;
               $break = TRUE;

I was a bit disappointed with using migration modules, and I quickly started using my own scripts. Below a script to import a taxonomy with hierarchy:

// You would first have to create an array $results from csv or other source
// Make sure you have tid, title and parent in your set
foreach($results as $result) {
    'tid' => $result->tid,
    'name' => $result->name,
    'vid' => 'MY_NEW_VOCABULARY'
// Reload and resave to add hierarchy 
foreach($results as $result) {
  $term = Term::load($result->tid);
  $term->parent = ['target_id' => $result->parent];
// Smile! You imported your tags while keeping their tid and hierarchy

For me this solve the problem:

  # Only attempt to stub real (non-zero) parents.
      plugin: skip_on_empty
      method: process
      source: parent
      plugin: migration_lookup
      migration: d7_taxonomy_term // this migration
    plugin: default_value
    default_value: 0
    source: '@parent_id'

Source: https://api.drupal.org/api/drupal/core%21modules%21taxonomy%21migrations%21d7_taxonomy_term.yml/8.6.x

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.