Skip to content

ConceptFor everyoneDrupal 11

Choose your path

You have a running site and have seen what the admin UI covers. Drupal work splits into four tracks with different skills and different documentation, and most developers live mainly in one. Pick yours here; if you come from another framework, the translation table below maps what you already know onto Drupal’s names for it.

The honest first question is not “which code do I write?” but “do I need code at all?”. Everything in Your first hour (content types, fields, listings, blocks, permissions) was configuration, and configuration is versionable and deployable like code. If you want a finished site rather than a development track, the Drupal CMS user guide covers the packaged product end to end, entirely in the admin UI. Reach for a track below when configuration stops being enough, and prefer the earliest track that solves your problem: a view before a custom controller, a theme override before a markup-altering module.

The tracks share one foundation: the ten core concept pages. Decoupled developers need entities and access first; module developers most of them early; theme developers mainly the render pipeline and caching. When a track page assumes a concept, it links it, so you can start from the track and backfill.

Drupal is built on Symfony components (the HTTP kernel, routing, the DI container, the console), so more of your knowledge transfers than the unfamiliar vocabulary suggests. The biggest mental shift is that Drupal’s data model and much of its behavior are defined in configuration rather than code; after that, the mapping is direct:

You know it asIn Laravel / Symfony / Next.jsIn DrupalStart here
Routingroutes/web.php, #[Route] attributes, file-based routesA *.routing.yml file per module mapping paths to controller classes, with access requirements declared on the routeRoutes and controllers
Data layer / ORMEloquent models, Doctrine entities, Prisma schemaThe Entity API: entity types in code, bundles and fields in configuration; query through entity storage, not SQLEntities, bundles, and fields
DI containerService container, autowiring, service providersThe same Symfony container: services in *.services.yml with autowiring, injected through constructorsServices and dependency injection
Middleware and eventsLaravel middleware and listeners, Symfony kernel eventsSymfony event subscribers for the request pipeline, plus hooks (attribute-based methods) for Drupal-specific extension pointsHooks and events
TemplatingBlade, Twig, JSX componentsTwig, selected by a template-suggestion naming convention instead of explicit render callsTwig in Drupal
Background workLaravel queues, Symfony MessengerThe Queue API with queue workers as plugins, processed on cron or by dedicated runners; Batch API for user-facing long operationsBackground processing
CLIartisan, bin/consoleDrush for day-to-day site operations, plus core’s own command-line application (vendor/bin/dr from Drupal 11.4; php web/core/scripts/drupal on 11.3 and earlier)Essential tools
Schema migrationsLaravel migrations, Doctrine migrationsConfig import for structure, update hooks for one-time data changes; there is no per-table migration fileConfiguration management
CachingCache facades, response cachingThe Cache API: declarative cache tags, contexts, and max-age attached to everything renderableCaching

Two warnings for framework developers, both learned the expensive way:

  • Do not reach for a controller first. In Laravel, a new page means a route and a controller. In Drupal, a listing page is a view, a landing page is content with a layout, and a settings page is a config form; custom controllers are for genuinely custom behavior. The earlier tracks are not the beginner versions, they are the shorter versions.
  • Do not treat entities as rows. Entity queries, loading, and saving go through services that fire hooks, enforce access, and maintain caches. Bypassing them with raw SQL works until the first cache or access bug it causes.

Was this page helpful?

Drupal is a registered trademark of Dries Buytaert.