A no-nonsense, battle-tested list for new (and not-so-new) Drupal developers in 2025. These are the lessons that would have saved me hundreds of hours of pain.
Most people treat Drupal like WordPress. That’s the fastest way to hate it.
I did this in 2012. I still have nightmares.
/core or /modules/contrib, stop immediately. Use a patch, a hook, a plugin, or a custom module instead.
# Export
drush config:export
# Import on another environment
drush config:import
# See differences
drush config:status
Doing this from day 1 saves you from the infamous “it works on my machine” hell.
Bad (what most beginners do):
composer create-project drupal/recommended-project
Good (what you should actually do):
composer create-project drupal/recommended-project my-site --no-interaction
cd my-site
composer require drupal/ctools drupal/token drupal/pathauto
Never download modules from drupal.org as zip files ever again.
Stop thinking everything has to be a “node.” Use custom entities (or even config entities) when appropriate.
| Feature | Paragraphs | Layout Builder | Custom Blocks |
|---|---|---|---|
| Reusable across content | Yes | No (per entity) | Yes |
| Per-node/section layout control | No | Yes | Limited |
| Performance | Medium | Lower | Best |
| Editor experience | Great | Excellent | Basic |
My rule of thumb in 2025: Use Paragraphs for reusable components, Layout Builder only when clients demand per-page freedom (and you have cache aggregation).
If your page is slow and you’re not using cache tags, you’re doing it wrong.
$build = [
'#markup' => $text,
'#cache' => [
'tags' => ['node:123'],
'contexts' => ['url'],
'max-age' => Cache::PERMANENT,
],
];
return $build;
# Clear cache
drush cr
# Update database after code changes
drush updatedb -y
# Enable a module
drush en module_name -y
# Generate a custom module (Drupal Console)
drupal generate:module
Install Admin Toolbar on every site. It turns the default admin menu from unusable to bearable.
Bad (Drupal 7 style):
<?php print $some_variable; ?>
Good:
{{ some_variable }}
Also: learn without, filter, Twig Tweak module, and drush twig:debug.
Views is incredibly powerful, but sometimes a simple EntityQuery or a custom controller is faster and cleaner.
In every custom module’s .services.yml and classes:
declare(strict_types=1);
Drupal 10+ runs beautifully on PHP 8.2 with attributes, enums, and readonly classes.
(Contributed by u/Stunning_Divide4298)
Do not resort to just what you know. It makes your life easier in the future. Example: Building a new theme today? Learn and use single directory components.
Drupal is not hard. It’s just different. Once you accept its philosophy (entities, dependency injection, configuration management, hooks/plugins/services), it becomes one of the most powerful and flexible systems on the planet.
Written by a Drupal developer who’s been burned by every mistake above — so you don’t have to be.