Allowing unlimited values for a field in programmatically defined form
I have set up a module demonstrating how to allow the user to add unlimited values:
https://bitbucket.org/scotteuser/drupal-8-demo-form-unlimited-values

Here is the Form itself:

&lt;?php

namespace Drupal\demo_form_unlimited_values\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;

/**
 * Class UnlimitedValuesForm.
 *
 * @package Drupal\demo_form_unlimited_values\Form
 */
class UnlimitedValuesForm extends FormBase {


  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'unlimited_values_form';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {

    // State that the form needs to allow for a hierarchy (ie, multiple
    // names with our names key).
    $form['#tree'] = TRUE;

    // Initial number of names.
    if (!$form_state-&gt;get('num_names')) {
      $form_state-&gt;set('num_names', 1);
    }

    // Container for our repeating fields.
    $form['names'] = [
      '#type' =&gt; 'container',
    ];

    // Add our names fields.
    for ($x = 0; $x &lt; $form_state-&gt;get('num_names'); $x++) {
      $form['names'][$x]['first_name'] = [
        '#type' =&gt; 'textfield',
        '#title' =&gt; $this-&gt;t('First name @num', ['@num' =&gt; ($x + 1)]),
      ];

      $form['names'][$x]['last_name'] = [
        '#type' =&gt; 'textfield',
        '#title' =&gt; $this-&gt;t('Last name @num', ['@num' =&gt; ($x + 1)]),
      ];
    }

    // Button to add more names.
    $form['addname'] = [
      '#type' =&gt; 'submit',
      '#value' =&gt; $this-&gt;t('Add another name'),
    ];

    // Submit button.
    $form['submit'] = [
      '#type' =&gt; 'submit',
      '#value' =&gt; $this-&gt;t('Submit'),
    ];

    return $form;
  }

  /**
    * {@inheritdoc}
    */
  public function validateForm(array &amp;$form, FormStateInterface $form_state) {
    parent::validateForm($form, $form_state);
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &amp;$form, FormStateInterface $form_state) {
    $values = $form_state-&gt;getValues();

    // Decide what action to take based on which button the user clicked.
    switch ($values['op']) {
      case 'Add another name':
        $this-&gt;addNewFields($form, $form_state);
        break;

      default:
        $this-&gt;finalSubmit($form, $form_state);
    }
  }

  /**
   * Handle adding new.
   */
  private function addNewFields(array &amp;$form, FormStateInterface $form_state) {

    // Add 1 to the number of names.
    $num_names = $form_state-&gt;get('num_names');
    $form_state-&gt;set('num_names', ($num_names + 1));

    // Rebuild the form.
    $form_state-&gt;setRebuild();
  }

  /**
   * Handle submit.
   */
  private function finalSubmit(array &amp;$form, FormStateInterface $form_state) {
    drupal_set_message($this-&gt;t('Do what you want with the final data here'), 'status');
  }

}


The critical bits are: 


$form[#tree] tells Drupal that the form is hierarchical.
$form_state-&gt;get() and $form_state-&gt;set() are used around the counter num_names
Check the 'op' to see which button the user pressed. If they pressed to add another field, use $form_state-&gt;set() to increase the count and $form_state-&gt;setRebuild(); to tell Drupal that the form should be rebuilt.


Hope that helps you get it working!