Using kint() or dump() to inspect form arraysfor Drupal 8 , 9 , 10 , and 11

Last updated :  

A form array is one of the most nested, sprawling data structures you'll ever work with in Drupal — a form with ten fields can easily produce a `$form` array with hundreds of keys once you count `#type`, `#title`, `#attributes`, `#states`, and every other property nested under every element. Trying to debug that by eye, scrolling through a `var_dump()`, is like trying to find one mislabeled folder in a filing cabinet by reading every page inside every folder. `kint()` and Symfony's `dump()` are the tools that turn that filing cabinet into a searchable, collapsible tree you can actually navigate.

What you'll learn in this lesson

  • Why raw `print_r()`/`var_dump()` output becomes unreadable for anything as deeply nested as a form array
  • How to install and enable the Devel module to get `kint()`
  • How to drop a debug call into `buildForm()` without breaking the form
  • The difference between `kint()` (Devel's formatter) and `dump()` (Symfony's built-in VarDumper)

Why form arrays specifically need a real inspector

Every render array property starts with `#`, and Form API elements nest deeply — a `#type => 'fieldset'` element contains child elements, each of which can carry its own `#states`, `#attributes`, `#ajax`, and so on. `print_r($form)` dumps all of that as flat, unindented text with no way to collapse anything you're not interested in. On a real form, that output can run to thousands of lines. `kint()` renders the same data as an interactive, collapsible tree in the page itself — you expand only the branches you care about.

Installing the Devel module

composer require drupal/devel
drush en devel -y

Devel is a contributed module, not part of core, so it needs to be pulled in via Composer like any other dependency. Once enabled, `kint()` becomes available as a global function anywhere in your module's PHP — no `use` statement required, since Devel registers it as a procedural helper.

Dropping kint() into a form's build method

namespace Drupal\my_module\Form;

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

class InspectForm extends FormBase {

  public function getFormId() {
    return 'inspect_form';
  }

  public function buildForm(array $form, FormStateInterface $form_state) {
    $form['example'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Example field'),
    ];

    kint($form);

    return $form;
  }

  public function submitForm(array &$form, FormStateInterface $form_state) {}

}

Placing `kint($form)` right before `return $form;` lets you inspect the array exactly as it will be rendered — every element you've added, plus whatever the parent class or any `hook_form_alter()` implementation elsewhere on the site has already contributed. The `kint()` output appears inline on the page itself, above the form, as a nested tree you can click through.

Never ship a `kint()` call. It's a debugging aid, not something that belongs in production code — it dumps potentially sensitive data (user input, entity values) straight onto the page for anyone viewing it. Remove every `kint()`/`dump()` call before committing, or better, wrap it in an environment check like `if (\Drupal::service('kernel')->getEnvironment() !== 'prod')` if you truly need it to persist through a deploy.

kint() vs. dump() — which one to reach for

`kint()` comes from the Devel module specifically and produces Drupal-aware, richly formatted output — object methods, inherited properties, and Drupal entity internals are all rendered legibly. `dump()` comes from Symfony's VarDumper component, which Drupal core already depends on, so it's available even without Devel installed. It's a lighter-weight, slightly less Drupal-specific formatter — genuinely useful when you can't install a new module (a locked-down production-adjacent environment, say) but still need better-than-`print_r()` output.

Quick check: you need to inspect a form array on a staging site where you can't install new contributed modules. Which function do you reach for — `kint()` or `dump()`? (Answer: `dump()` — it ships with Symfony's VarDumper, a core dependency, so it's already available with zero new modules installed. `kint()` requires the Devel module specifically.)

Key takeaways

  • `print_r()`/`var_dump()` become unreadable on deeply nested form arrays — reach for a real inspector instead.
  • `kint()` requires the Devel module (`composer require drupal/devel` + enable) but gives the richest, most Drupal-aware formatting.
  • `dump()` ships with Symfony's VarDumper, a core dependency, so it works even without installing anything extra.
  • Place your debug call right before `return $form;` in `buildForm()` to see the array exactly as it will render, including anything added by `hook_form_alter()`.
  • Never leave a `kint()`/`dump()` call in code you ship — it exposes internal data on the live page.

Coming up next

Inspecting the form's structure is only half the debugging story — the other half is figuring out why a validation rule isn't firing the way you expect. In the next lesson, we'll look at exactly that: tracing why `setErrorByName()` calls do or don't appear, and how `$form_state` carries validation state between requests.