---
url: 'https://metadrop.net/en/articles/drupal-cli-in-core-finally-landed-in-114-how-and-why-we-got-here'
title: 'Drupal CLI in core finally landed in 11.4, how and why we got here'
author:
  - 'Jorge Tutor'
  - 'Ricardo Sanz'
date: '2026-10-22T14:00:40+00:00'
updated: '2026-10-23T10:26:38+00:00'
type: article
summary: 'Drupal 11.4 includes dr, an experimental command-line interface in core that discovers Symfony Console commands from core and contrib modules. The article explains why Drupal needs an internal CLI, why the attempts of 2014 and 2019 stalled, and which changes in 2026 allowed it to land. It then describes what dr runs in 11.4, the options for making contrib commands work with both Drush and dr, why deployments still depend on Drush, and why remote site management based on site aliases and sql:sync will likely need a different workflow.'
tags:
  - 'Drupal Planet'
  - Drush
  - Drupal
  - 'Drupal CLI'
  - Community
image: 'https://metadrop.net/sites/default/files/styles/full/public/2026-10/drush_logo-black.png.webp?itok=bbbmnTeS'
files:
  - 'https://metadrop.net/sites/default/files/2026-10/2026-drupal-cli-drush.pdf'
published: true
og:
  site_name: Metadrop
  'image:type': image/webp
  'image:width': '300'
  'image:height': '296'
  'image:alt': 'Drupal CLI in core finally landed in 11.4, how and why we got here'
  locale: en_US
  'locale:alternate': es_ES
schema:
  '@context': 'https://schema.org'
  '@graph':
    -
      '@type': Article
      '@id': 'https://metadrop.net/en/articles/drupal-cli-in-core-finally-landed-in-114-how-and-why-we-got-here#article'
      name: 'Drupal CLI in core finally landed in 11.4, how and why we got here'
      headline: 'Drupal CLI in core finally landed in 11.4, how and why we got here'
      description: 'Drupal 11.4 includes dr, an experimental command-line interface in core that discovers Symfony Console commands from core and contrib modules. The article explains why Drupal needs an internal CLI, why the attempts of 2014 and 2019 stalled, and which changes in 2026 allowed it to land. It then describes what dr runs in 11.4, the options for making contrib commands work with both Drush and dr, why deployments still depend on Drush, and why remote site management based on site aliases and sql:sync will likely need a different workflow.'
      about:
        - Drush
        - Drupal
        - 'Drupal CLI'
        - Community
      image:
        '@type': ImageObject
        url: 'https://metadrop.net/sites/default/files/styles/full/public/2026-10/drush_logo-black.png.webp?itok=bbbmnTeS'
        width: '300'
        height: '296'
      datePublished: '2026-10-22T16:00:40+02:00'
      dateModified: '2026-10-23T12:26:38+02:00'
      author:
        -
          '@type': Person
          name: 'Jorge Tutor'
        -
          '@type': Person
          name: 'Ricardo Sanz'
      publisher:
        '@type': Organization
        '@id': 'https://metadrop.net/#organization'
      mainEntityOfPage: 'https://metadrop.net/en/articles/drupal-cli-in-core-finally-landed-in-114-how-and-why-we-got-here'
    -
      '@type': Organization
      '@id': 'https://metadrop.net/#organization'
      url: 'https://metadrop.net/'
      name: Metadrop
      sameAs:
        - 'https://www.drupal.org/metadrop'
        - 'https://x.com/metadrop'
        - 'https://asociaciondrupal.es/partner/metadrop'
        - 'https://www.linkedin.com/company/metadrop'
      telephone: '+34910053180'
      contactPoint:
        '@type': ContactPoint
        telephone: '+34910053180'
        email: hola@metadrop.net
        availableLanguage:
          - Spanish
          - English
        contactType: 'customer service'
      logo:
        '@type': ImageObject
        url: 'https://metadrop.net/modules/custom/metadrop_schema/images/logo-metadrop-500-500.jpg'
        width: '500'
        height: '500'
      address:
        '@type': PostalAddress
        streetAddress: 'Calle Virgen de Nuria 23'
        addressLocality: Madrid
        addressRegion: Madrid
        postalCode: '28027'
        addressCountry: ES
    -
      '@type': ItemPage
      '@id': 'https://metadrop.net/en/articles/drupal-cli-in-core-finally-landed-in-114-how-and-why-we-got-here'
      breadcrumb:
        '@type': BreadcrumbList
        itemListElement:
          -
            '@type': ListItem
            position: 1
            name: Home
            item: 'https://metadrop.net/en'
          -
            '@type': ListItem
            position: 2
            name: 'Expert Drupal & Tech Articles'
            item: 'https://metadrop.net/en/articles'
      publisher:
        '@type': Organization
        '@id': 'https://metadrop.net/#organization'
---
 1. [Articles](https://metadrop.net/en/articles)
 
  

# Drupal CLI in core finally landed in 11.4, how and why we got here

Thursday, October 22, 2026

 

 



Drupal 11.4 includes dr, an experimental command-line interface in core that discovers Symfony Console commands from core and contrib modules. The article explains why Drupal needs an internal CLI, why the attempts of 2014 and 2019 stalled, and which changes in 2026 allowed it to land. It then describes what dr runs in 11.4, the options for making contrib commands work with both Drush and dr, why deployments still depend on Drush, and why remote site management based on site aliases and sql:sync will likely need a different workflow.





   



Drush is part of almost every serious Drupal project: it rebuilds caches, runs database updates, imports configuration and drives deployments. With **Drupal 11.4, core ships its own command-line tool,** `<strong>dr</strong>`**, and the** [**initiative behind it**](https://www.drupal.org/community-initiatives/cli-in-core-initiative "CLI in Core Initiative") **openly aims to replace Drush over time**. The tool is still experimental, but the transition has started, and the parts of daily work that depend on Drush, especially CI/CD pipelines and remote operations, will not all move at the same pace. Knowing where things stand now avoids being wrong-footed later.

## Drupal has depended on an external tool for its daily operations at a cost

Drush is the de facto CLI for Drupal. All CLI operations (rebuilding caches, running database updates, importing configuration, driving deployments) go through it, and **it lives outside core**. Core's own script, `core/scripts/drupal`, added in 2018 ([\#2911319](https://www.drupal.org/project/drupal/issues/2911319 "Provide a single command to install & run Drupal")), was not extensible and only shipped three built-in commands: quick-start, install and generate-theme.

 

 

Discoverability was one of the problems: a Drupal CLI only appears after requiring the package `drush/drush`, so it is not obvious that a Drupal CLI tool exists for newcomers. But the **real burden is keeping two separate projects in step**, Drush and Drupal core. Every Symfony upgrade in core forced a new Drush release and broke Composer updates, as happened with Drupal 8.4 and Symfony 3, and again with Drupal 9 and Symfony 4. Sites had to wait for Drush to catch up.

**An internal CLI would be easy to find for everyone and removes the version-sync problem**. As catch, a core committer, put it in ["CLI entry point in Drupal Core"'s comment #47](https://www.drupal.org/project/drupal/issues/3453474#comment-16514961): "drush also has to support multiple versions of core, but a command in core only has to support the version it's in (e.g. an command in 11.x doesn't need to work with 12.x or 10.x)." **Commands in core also follow the core tests and backwards compatibility policy**. And this internal CLI provides one standard way to provide commands, instead of choosing between Drush or custom scripts (or Drupal Console when it was in use).

The counterargument made sense as well. Drush is proven and widely used, so why rebuild it? "Instead of reinventing the wheel we could promote Drush instead or even include it in our composer.json as a requirement" hchonov wrote in 2019 ([\#3089277](https://www.drupal.org/project/drupal/issues/3089277#comment-13319473 "Provide core CLI commands for the most common features of Drush")).

Finally, **core chose its own CLI because a Composer dependency on Drush creates a two-way coupling**: core changes can break Drush, and Drush has to follow core's Symfony versions. Core commands only depend on core. Agreeing on that direction, though, took a long time.

## Ten years of the same debates

The **first attempt** ([\#2242947](https://www.drupal.org/project/drupal/issues/2242947 "Integrate Symfony Console component to natively support command line operations")) was opened in 2014 and collected 214 comments before it was closed as outdated in 2026. **The second** ([\#3089277](https://www.drupal.org/project/drupal/issues/3089277 "Provide core CLI commands for the most common features of Drush")) was opened in 2019 in the Ideas queue and ended in "[the same kind of inertia](https://www.drupal.org/project/drupal/issues/2242947#comment-14695035)".

Both **were blocked by the same recurring issues**, and each position was reasonable at the time:

- **Overlap with Drush:** core did not want two approaches, and Drush had not committed to using a core CLI.
- **Release timing:** the work was deferred to 8.1.x to avoid disrupting the Drupal 8 release, then pushed from minor to minor.
- **Name:** the `drupal` binary was already taken by Drupal Console, which could not be renamed without breaking its users.
- **Bootstrap:** commands needed to run with and without a booted Drupal, and the kernel was tightly coupled to HTTP.
- **Discovery:** the design never converged between plugins, services, separate containers and composer `extra`.
- **Ownership:** there was broad agreement that it was a good idea, but nobody to implement and drive it.

By 2022, even Moshe Weitzman, the lead Drush maintainer, backed bundling Drush in the project templates instead of a core CLI. **Four years later, every one of these blockers had an answer**.

## What changed in 2026

Moshe probably laid the **first stone with his post** [**Drush's Final Act**](https://weitzman.github.io/blog/drush-final-act) in February. He stated "attempts stalled due to debates about command name or bootstrap details or numerous other bikeshed details."

He made the competitive pressure explicit: "**I think it is vital for Drupal from a competitive perspective to get to a full featured CLI quickly**." He also stated his goal for the tool he maintains: "My end goal here is the death of Drush. It has served an incredibly long and useful life. Its death will be its most impactful and generous act."

The technical blockers fell first. **Drush converted all its commands to vanilla Symfony Console**, so any Symfony Console application can discover them. Drupal Console was officially sunset in April 2025, which **removed the second competing tool**. Its maintainers framed the sunset as a success, since Drush absorbed its interactive features and modern Symfony components: "So the project is sunsetting, not because it failed, but because it succeeded" ([Drupal Console project page](https://www.drupal.org/project/console)), something we can probably agree on.

 

 

  Group picture of Drupal Dev Days Athens 2026, one of the events where the community talked about all of this. Source: https://www.flickr.com/photos/204480346@N05/55226423971/in/pool-dddathens2026/  Bootstrap stopped being a blocker as well. Only a few commands, like `site:install`, need a non-booted site but it was thought this required a lot of complexity to support. However, [greg.1.anderson showed that overriding `Application::find()`, about a dozen lines and the same approach Drush has used since Drush 9](https://www.drupal.org/project/drupal/issues/3453474#comment-15640836), **lets bootstrapped and non-bootstrapped commands share one script, avoiding that complexity**. Core also adopted `symfony/runtime` ([\#3313404](https://www.drupal.org/project/drupal/issues/3313404 "Use symfony/runtime for less bespoke bootstrap/compatibility with varied runtime environments")), which moves environment setup out of `DrupalKernel` into a reusable layer shared by HTTP and CLI entry points, **reducing the custom bootstrap code** each had to maintain separately.

Discovery settled on a standard Symfony mechanism: **a compiler pass picks up classes in** `<strong>src/Command/</strong>` **with** `<strong>#[AsCommand]</strong>`, with no custom design needed.

Finally, the people aligned. In the [issue](https://www.drupal.org/project/drupal/issues/3453474#comment-16495154), [Dries Buytaert confirmed agreement](https://www.drupal.org/project/drupal/issues/3453474#comment-16495154): "There is agreement that a system-wide CLI would be a good thing for Drupal." **The CLI in Core community initiative (**[**\#3582246**](https://www.drupal.org/project/drupal/issues/3582246 "[meta] CLI in Core community initiative")**, #cli-in-core on Drupal Slack) formed around that agreement**, with the Drush lead, core committers and a roadmap.

Disagreements still came up, and each was settled on its own. Moshe first proposed depending on Drush temporarily to move fast. catch raised the risk of getting stuck halfway with a two-way dependency, Moshe agreed to drop it, and the plan became bringing the essential commands into core one by one. The name, with `dex`, `drupal` and `dr` on the table, went to its own policy issue ([\#3583795](https://www.drupal.org/project/drupal/issues/3583795 "[policy] Decide naming the new CLI entry point to dr")) so it would not block the code. The **result was** `<strong>dr</strong>`**, in line with short CLIs like** `<strong>wp</strong>`**,** `<strong>ng</strong>` **or** `<strong>gh</strong>`.

Another question was timing. **Shipping in 11.x won over waiting for Drupal 12**. In longwave's words ([\#125](https://www.drupal.org/project/drupal/issues/3453474#comment-16599886)), shipping early means "users can slowly migrate to `dr` commands while keeping the `drush` fallback for the time being, and secondly, that adding the CLI in 11.x inspires people to open MRs to add their favourite/most used commands in time for Drupal 12."

The timeline shows how quickly things moved once the pieces were in place. dpi opened ([\#3453474](https://www.drupal.org/project/drupal/issues/3453474 "CLI entry point in Drupal Core")) in June 2024. Initial work was done, but it stalled for about 18 months. Moshe revived it in February 2026, and **larowlan committed it on June to main, 11.x and 11.4.x**: "Committed to main and 11.x. Backported to 11.4.x. Congrats all!" ([\#144](https://www.drupal.org/project/drupal/issues/3453474#comment-16610933)).

## What `dr` ships in Drupal 11.4

**The new CLI runs as** `<strong>vendor/bin/dr</strong>`, implemented in `core/scripts/dr`. In DDEV, `ddev exec dr` works because `vendor/bin` is in the web container PATH. It discovers Symfony Console commands in core and contrib through the Symfony Runtime component, so caches can be rebuilt and cron can run without Drush. `core/scripts/drupal` is deprecated in favour of `vendor/bin/dr`.

The main commands available in 11.4.0 are the ones the previous core script provided: `generate-theme`, `install` and `quick-start`, along with `cache:rebuild`, `content:export`, `system:cron`, `system:status` and commands for recipes (`recipe:apply` and `recipe:info`). **Several map directly to familiar Drush commands**:

```bash
drush cr        →  dr cr          # Alias of cache:rebuild
drush cron      →  dr cron        # Alias of system:cron
drush status    →  dr status      # Alias of system:status
drush si        →  dr install     # install using a profile or a recipe
drush recipe    →  dr recipe      # Alias of recipe:apply

```

`<strong>dr</strong>` **is marked** `<strong>@internal</strong>` **and experimental** in the [change record](https://www.drupal.org/node/3584928), and the roadmap to stable ([\#3606055](https://www.drupal.org/project/drupal/issues/3606055 "[meta] CLI entry point roadmap to stable")) is still active. Drush keeps working during the transition, which leaves time for contrib modules to adapt.

## Contrib commands: the options at a glance

Writing and porting commands is already documented in the official [Drush command porting guide to the new dr Drupal core CLI](https://www.drupal.org/docs/develop/drupal-apis/command-line-interface-cli-api/drush-command-porting-guide-to-the-new-dr-drupal-core-cli) and in the [change record](https://www.drupal.org/node/3584928). The model fits in one line: **a plain Symfony Console command, a class with** `<strong>#[AsCommand]</strong>` **in the module's** `<strong>src/Command/</strong>` **directory**, auto-discovered by core, with no `drush.services.yml`.

There are **two ways to support both tools during the transition**. The first is a plain Symfony Console command, which both Drush and `dr` discover. Recent Drush already uses Symfony Console commands, so many need little or no work. The second is the Service Wrapper Pattern, for commands that rely on Drush features such as output formatters (`--format`). The business logic goes in a Drupal service. Two thin command classes call it: one for `dr` (a plain Symfony Console command in `src/Command/`, auto-discovered), one for Drush (in `src/Drush/Commands/`, registered in `drush.services.yml`). Neither wrapper contains logic, so nothing is duplicated.

Local commands are the easy part, though.

## Remote site management will likely need a new workflow

The biggest difference from the Drush model **is where the site the tool manages sits**: `dr` works only against the local Drupal instance. It has no site aliases, and the roadmap to stable does not list any remote command. Because remote commands depend on site aliases, and aliases are not planned, **remote commands will most likely not be covered by** `<strong>dr</strong>` either.

Moshe, who is also the technical lead of the initiative, **expects aliases to go**: "Along the way, we may lose some niceties like Drush config and Site aliases. Platforms already have solutions for replacements aliases such as Lagoon (Amazee), Terminus (Pantheon), acli (Acquia), etc." He also points to generic tools such as Pssh, Fabric or `ash`, a Drush-centric alias tool by jonpugh.

**Managing remote sites will probably require a shift or adaptation in the workflow or tooling**, for example running `dr` inside each environment over SSH, in the container or through the hosting platform CLI or a module or tool in the contrib space, instead of targeting it from a local machine with an alias. Daily CI/CD work is directly affected: `drush sql:dump` and `drush sql:sync` between environments are common steps in pipelines. `sql:*` commands are only listed in the roadmap, with no issue yet, and a sync between two sites is a remote operation by nature. **How the community will solve remote management is still unclear**, and it is probably a topic for another article.

## Deployments still need Drush

Separate from remote management, the deployment pipeline itself has gaps at the command level. Deployments face a simpler gap: **several commands they rely on are not in** `<strong>dr</strong>` **yet**. As of October, 2026, only 4 of the 14 commands on the roadmap to stable ([\#3606055](https://www.drupal.org/project/drupal/issues/3606055 "[meta] CLI entry point roadmap to stable")) are available in 11.4.0, and `site:install` only with limits. However, some others are already "Fixed" and can be expected in a following stable release. The table below covers the roadmap commands plus a few others mentioned in this or other issues:

| Drush command | `dr` status | Issue |
|---|---|---|
| `cache:rebuild` | Shipped in 11.4.0 |  |
| `core:cron` | Shipped in 11.4.0 (`system:cron`) |  |
| `core:status` | Shipped in 11.4.0 (`system:status`) |  |
| `site:install` | Shipped (`install`), limited. Install with any DB driver: Needs work | [\#3594342](https://www.drupal.org/project/drupal/issues/3594342), [\#3594320](https://www.drupal.org/project/drupal/issues/3594320) |
| `user:login` | Fixed in dev branch (11.x) | [\#3594332](https://www.drupal.org/project/drupal/issues/3594332) |
| `pm:install` | Fixed in dev branch (11.x) | [\#3594334](https://www.drupal.org/project/drupal/issues/3594334) |
| `pm:uninstall` | Fixed in dev branch (main) | [\#3594335](https://www.drupal.org/project/drupal/issues/3594335) |
| `pm:list` | Fixed in dev branch (main) | [\#3594336](https://www.drupal.org/project/drupal/issues/3594336) |
| `config:export` | Fixed in dev branch (main) | [\#3594337](https://www.drupal.org/project/drupal/issues/3594337) |
| `config:import` | Needs review | [\#3594338](https://www.drupal.org/project/drupal/issues/3594338) |
| `config:status` | Active (postponed on another issue) | [\#3594339](https://www.drupal.org/project/drupal/issues/3594339) |
| `updatedb` | Active | [\#3594333](https://www.drupal.org/project/drupal/issues/3594333) |
| `updatedb:status` | Active | [\#3594340](https://www.drupal.org/project/drupal/issues/3594340) |
| `sql:drop`, `sql:query` | Listed in the roadmap, no issue yet |  |
| `watchdog:show` | Listed in the roadmap, no issue yet |  |
| `deploy` | Mentioned as missing by longwave ([\#125](https://www.drupal.org/project/drupal/issues/3453474#comment-16599886)), no issue yet |  |

With `updatedb`, `config:import` and `deploy` still missing, **the practical approach is to keep Drush in deployment scripts for now and use** `<strong>dr</strong>` **alongside it**. Not every Drush command will move to core either, since implementing every Drush command is listed as "Not in scope" in the initiative ([\#3582246](https://www.drupal.org/project/drupal/issues/3582246 "[meta] CLI in Core community initiative")). Drush stays for the rest, and contrib commands need porting, or plain Symfony discovery, to work with `dr`.

**Other gaps are still open**: there is no table formatting standard yet ([\#3611694](https://www.drupal.org/project/drupal/issues/3611694 "Decide and implement table formatting for console command output")), help for invokable commands does not show their usage ([\#3606744](https://www.drupal.org/project/drupal/issues/3606744 "Invokable commands don't show their usages in help")), commands in subdirectories with a period in the name are not discovered ([\#3594184](https://www.drupal.org/project/drupal/issues/3594184 "Commands in subdirectories with a period in the name are not discovered")), there is an 11.4.4 logger regression ([\#3612206](https://www.drupal.org/project/drupal/issues/3612206 "LoggerAwarePass crashes container compilation when DrupalConsoleLogger is decorated")) and user guide documentation is pending ([\#3625734](https://www.drupal.org/project/drupal/issues/3625734 "User guide documentation for dr")). The roadmap targets the essential commands for Drupal 12.0.0, with a feature-complete set most likely in a minor release in 2027.

## Conclusion

**A CLI in core removes a decade-old dependency on an external tool** for basic operations. This time the conditions are in place: Drush is ready to step aside, core committers are aligned, the old blockers have answers and the code has shipped.

**The transition has started**, and knowing it now avoids being wrong-footed, especially on remote operations. `dr` works locally and site aliases are not planned, so workflows built on aliases and `sql:sync` will likely need more than replacing `drush` with `dr`. Until then, **Drush remains necessary for remote work and deployments**. What lands next depends on usage and feedback.

We got here for a practical reason. **We are adding** `<strong>dr</strong>` **support to our own modules**, and that work is still in progress. Understanding what was going on meant digging through drupal.org issues with hundreds of comments, a change record, a porting guide, blog posts and ten years of history. **We used AI to help collect and read all of it**. After following that history, this looks like the attempt that will stick, and once the picture was in one place, we decided to share it.

**Start porting your contrib modules to** `<strong>dr</strong>`, explore it on real projects and share the urgent needs you find in the #cli-in-core Slack channel or the [CLI in Core initiative](https://www.drupal.org/project/drupal/issues/3582246), because **Drupal moves forward with community help**.



 [      Download 2026-drupal-cli-drush.pdf (PDF, 594.25 KB)  ](https://metadrop.net/sites/default/files/2026-10/2026-drupal-cli-drush.pdf)

 

[Drush](https://metadrop.net/en/articles?text=Drush)

[Drupal](https://metadrop.net/en/articles?text=Drupal)

[Drupal CLI](https://metadrop.net/en/articles?text=Drupal%20CLI)

[Community](https://metadrop.net/en/articles?text=Community)

 

- Jorge Tutor
    
    CIO
- Ricardo Sanz
    
    CTO
 
 One partner across the Drupal lifecycle 

[Drupal development, solutions and support across the platform lifecycle](https://metadrop.net/en/services/drupal " See Drupal development, solutions and support across the platform lifecycle")

Metadrop is a Drupal specialist covering the whole platform lifecycle: architecture advice, build, multisite and headless solutions, version upgrades and long-term maintenance for organizations running business-critical Drupal in Europe.

 

 See more