Import CSV to nodes/entities in Drupal 8 including a UI What’s the best solution for importing CSV files into nodes or entities in Drupal 8 that offers a UI so content editors can import regularly?

I’ve heard D8 Migrate works well but I understand there’s currently no UI for the import process.

CSV import via Feeds doesn’t appear to be ready yet.
I do this all the time, making use of migration configuration entities (provided by the migrate_plus module). Define a migration plugin in your migration module's config/install directory, using the CSV source plugin from the migrate_source_csv module - omitting the 'path' source configuration, which will be filled in from the form. Let's say the ID of this migration is example_csv. Create a form with a file upload element (named 'csv_file' in this case), and in the submitForm() method:

  public function submitForm(array &amp;$form, FormStateInterface $form_state) {
    $all_files = $this-&gt;getRequest()-&gt;files-&gt;get('files', []);
    if (!empty($all_files['csv_file'])) {
      $validators = ['file_validate_extensions' =&gt; ['csv']];
      if ($file = file_save_upload('csv_file', $validators, 'public://', 0)) {
        $csv_migration = Migration::load('example_csv');
        $source = $csv_migration-&gt;get('source');
        $source['path'] = $file-&gt;getFileUri();
        $csv_migration-&gt;set('source', $source);
        $csv_migration-&gt;save();
        drupal_set_message($this-&gt;t('File uploaded as @uri.', ['@uri' =&gt; $file-&gt;getFileUri()]));
      }
      else {
        drupal_set_message($this-&gt;t('File upload failed.'));
      }
    }
  }


This updates the migration settings with the new file. You still have to run the migration using drush mi example_csv to actually import the content.

Or add some code to the function to actually execute the import:

      $migration_instance = \Drupal::service('plugin.manager.migration')-&gt;createInstance('example_csv');

      $executable = new MigrateExecutable($migration_instance, new MigrateMessage());

      try {
        $migration_status = $executable-&gt;import();
      }
      catch (\Exception $e) {
        \Drupal::logger('migrate_drupal_ui')-&gt;error($e-&gt;getMessage());
        $migration_status = MigrationInterface::RESULT_FAILED;
      }
      if ($migration_status) {
        drupal_set_message($this-&gt;t('Import Successful'));
      }
      else {
        drupal_set_message($migration_status, 'error');
      }