Skip to header Skip to main navigation Skip to main content Skip to footer
Cookies UI
Alaa Haddad Offers Exceptional Drupal Custom Theming and Modules in Austin TX Alaa Haddad - Drupal Expert
Main navigation
  • Professional Profile
  • Drupal Services
    • Drupal Consultant
    • Drupal Architect
    • Drupal Developer
    • Drupal Themer
  • My Drupal Modules & Themes
      • Cloudflare Purge
      • Solo Copy Blocks
      • W3CSS Paragraphs
      • Paragraphs Bundles
      • Acquia Purge Varnish
      • Reference Blocked Users
      • Module Matrix
      • Paragraphs Bundles Import
      • Selectify
      • Solo Utilities
      • Utilikit
      • Solo
      • Amun
      • Anhur
      • Amunet
      • W3CSS Theme
      • 3D Carousel
      • 3D FlipBox
      • Accordion
      • Carousel
      • Hero
      • Lightbox
      • Parallax
      • Reveal
      • Slideshow
      • Tabs
  • Blog
  • Videos
  • Contact
  • Hire Me (opens in new tab)
Search form
User login
CAPTCHA
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.
  • Reset your password
User account menu
  • Hire Me (opens in new tab)
  • Drupal Services
  • Blog
Site branding
Alaa Haddad - Drupal Expert
Consultant • Architect • Developer • Themer - Expert Drupal Solutions
Article Title Image - Block 1

Drupal Development Services: Custom Modules, Entity API, and Code That Lasts

Content Info - Article Info
Alaa Haddad, professional Drupal developer based in Austin, TX   Alaa Haddad
  4:23 PM CDT, Fri September 11, 2026
Share

Breadcrumbs

Breadcrumb

  • Home
  • Drupal Developer
  • Drupal Development Services: Custom Modules, Entity API, and Code That Lasts

Main page content

Drupal development covers a wide range of work, and the word means different things to different people. To a site owner it often means "make the website do this new thing." To a developer it means deciding whether that new thing belongs in configuration, in a contributed module, in custom code, or in the theme — and living with that decision for the next several years.

That decision is the part that costs money later. A site assembled from whatever was quickest at the time still works on launch day. It becomes expensive at the first major version upgrade, when every shortcut has to be understood again by somebody who was not there when it was taken.

This page describes how I approach Drupal development, what belongs in custom code, the mistakes that show up most often in codebases I am asked to review, and how to tell whether a piece of work is something your team should do or something worth bringing in help for.

What Drupal Development Actually Covers

It helps to separate four kinds of work that often get grouped under one heading:

  • Site building — content types, fields, views, and display modes, configured through the admin interface and exported as configuration.
  • Theming — templates, CSS, and the presentation layer. A separate discipline with its own rules, covered on the Drupal themer page.
  • Custom module development — behaviour that Drupal and contributed modules do not already provide: business logic, integrations, custom entities, access rules, queue workers.
  • Integration — connecting Drupal to payment providers, CRMs, search services, data warehouses, or internal APIs.

Most real projects need some of each. The skill is knowing which layer a requirement belongs in, because putting logic in the wrong layer is what makes a site hard to maintain.

Why This Matters More Than It Used To

Drupal has changed considerably. Recent versions have moved steadily toward modern PHP: dependency injection instead of global functions, PHP attributes instead of docblock annotations for plugin discovery, and object-oriented hook implementations instead of procedural functions in a .module file.

These are improvements. They also mean that code written against older idioms accumulates upgrade debt quietly. It keeps working, right up until a major version where it does not, and then the bill arrives all at once.

The practical consequence is that "does it work?" is no longer a sufficient standard for custom code. The better question is whether the code is written the way current Drupal expects, because that is what determines the cost of the next upgrade.

The First Decision: Configuration, Contrib, or Code

The cheapest custom code is the code you do not write. Before opening an editor, the order of preference is:

  • Configuration first. If a content type, a view, or a display mode solves it, solve it there. Configuration is exportable, reviewable, and survives upgrades with minimal attention.
  • A contributed module second. If a well-maintained module already solves the problem, use it. Someone else is carrying the maintenance burden and the security coverage.
  • Custom code last — and deliberately, when the requirement is genuinely specific to your business.

The failure mode in both directions is real. Writing a custom module for something Views already does creates permanent maintenance work. Installing fifteen contributed modules to avoid writing forty lines of code creates a different burden: fifteen more things to keep updated and to test at every upgrade.

The judgement is in whether the requirement is generic or specific. Generic requirements have generic solutions already. Specific ones usually deserve code you control.

Where Custom Modules Belong — and Where They Do Not

A useful boundary: modules provide behaviour, themes provide presentation, and configuration describes structure. When those blur, maintenance gets harder.

Markup and CSS in a module is the most common violation. It works, but it means presentation changes require a developer instead of a themer, and it means the module cannot be reused on a site with a different theme. Modules should emit render arrays and provide templates that a theme can override, not hard-code appearance.

The reverse also happens: business logic inside .theme preprocess functions. It runs, but it is invisible to anyone reading the module layer, and it disappears the moment the site is re-themed.

Work With the Entity API, Not Around It

Nearly everything in Drupal is an entity: nodes, users, taxonomy terms, media, custom entity types you define yourself. The Entity API gives you access control, revisions, translation, validation, caching, and a consistent query layer.

Code that bypasses it — usually direct SQL against tables like node_field_data — gives up all of that silently. It ignores access checks, misses cache invalidation, and breaks when the storage schema changes underneath it.

// Bypasses access control, revisions, and cache invalidation.
$titles = $database->query("SELECT title FROM node_field_data WHERE status = 1")
  ->fetchCol();

// Uses the entity query, which respects access and cacheability.
$nids = $entityTypeManager->getStorage('node')->getQuery()
  ->condition('status', 1)
  ->accessCheck(TRUE)
  ->execute();

There are legitimate reasons to drop to the database layer — large reporting queries and migrations among them — but it should be a deliberate exception with a comment explaining why, not the default way data gets read.

Hooks Are Becoming Classes

For most of Drupal's history, hooks were procedural functions named after your module. Recent versions support implementing them as methods on a class, discovered through an attribute:

namespace Drupal\my_module\Hook;

use Drupal\Core\Hook\Attribute\Hook;
use Drupal\node\NodeInterface;

class NodeHooks {

  #[Hook('node_presave')]
  public function nodePresave(NodeInterface $node): void {
    // Logic that used to live in my_module_node_presave().
  }

}

This is worth adopting for new code. Hook classes are services, so they receive their dependencies through the constructor instead of reaching for \Drupal::service(), which makes them testable in isolation. It also gets you ahead of a migration that will otherwise have to happen later, under time pressure.

Plugins and the Move to Attributes

Blocks, field widgets, field formatters, and many other extension points are plugins. Historically they were discovered by reading docblock annotations. Newer Drupal reads PHP attributes instead:

#[FieldWidget(
  id: 'my_module_color_widget',
  label: new TranslatableMarkup('Color picker'),
  field_types: ['string'],
)]
class ColorWidget extends WidgetBase {}

If you maintain contributed modules, this is the change most likely to bite. A plugin class carrying only an annotation continues to work while the plugin manager still supports annotation discovery — and then stops working entirely when that support is removed. The failure is a fatal error, not a deprecation notice, so it will not show up in a log you can ignore for a release or two.

Maintaining 27+ contributed modules has taught me to treat this kind of change as scheduled work rather than as an emergency, because the alternative is discovering it on the day of an upgrade across every site at once.

Configuration Management Is Part of Development

Configuration — content types, fields, views, permissions — lives in the database on a running site and is exported to YAML files for version control:

drush config:export
drush config:import

Two things routinely go wrong here.

The first is drift: someone changes a view in the production admin interface, nobody exports it, and the next deployment silently reverts their change. Configuration only works as a source of truth if every change flows through it.

The second is the boundary between configuration and content. Nodes, blocks placed as content, media items, and taxonomy terms are content, and content does not travel through configuration management. It is a common and expensive surprise: a page built and tested on a staging site does not appear in production, because it was never configuration in the first place.

If your team is fighting configuration drift or unexplained reverts on deployment, that is usually a workflow problem rather than a Drupal problem — and it is worth a short conversation before it becomes habit.

Performance Is a Development Concern

Performance is often treated as something to fix at the hosting layer after launch. Much of it is decided while the code is being written.

Drupal's render system caches aggressively, but only when the code tells it what a piece of output depends on. Every render array can declare cache tags, contexts, and a max-age. Omit them and you get one of two outcomes: output cached too aggressively and served stale, or code that disables caching entirely to be safe and makes every request expensive.

$build = [
  '#markup' => $text,
  '#cache' => [
    'tags' => $node->getCacheTags(),
    'contexts' => ['user.permissions'],
  ],
];

Getting cacheability right in the code is what makes edge caching safe further out. A page that declares its dependencies correctly can be cached for a long time and invalidated precisely when its content changes.

Testing What You Build

Drupal ships a serious testing framework, and custom modules that carry tests are markedly cheaper to maintain. The practical value is not proving the code works today — it is knowing at the next core update whether it still does.

Not everything needs the same treatment. Business rules with real consequences, access logic, and anything touching payments or personal data deserve tests. A block that renders three fields does not need the same investment. Match effort to what breaking it would cost.

Common Mistakes I See in Drupal Codebases

  • Core or contrib modules edited directly. The change disappears at the next update. Use hooks, plugins, or a patch tracked in composer.json.
  • Everything in one custom module. A single module handling twelve unrelated concerns cannot be tested, reused, or removed.
  • Caching disabled to fix a bug. This converts a correctness problem into a permanent performance problem, and the original bug is still there.
  • Access checks in the theme layer. If a template decides who sees something, the data was already loaded and is often still reachable through JSON:API or a view.
  • Configuration changed in production and never exported. Guarantees the change will be reverted, usually at the worst moment.
  • Composer bypassed. Modules downloaded and unzipped by hand cannot be updated predictably and drop out of security tooling.

None of these are exotic. They are ordinary decisions that were reasonable under deadline and never revisited.

Security Belongs in the Code

Most Drupal security incidents are not exotic exploits. They are unapplied updates and custom code that skipped a check.

The habits that matter: run access checks on entity queries rather than filtering results afterwards; use the database abstraction layer with placeholders rather than building SQL strings; let Twig autoescape output rather than marking it safe to silence a warning; keep dependencies updated through Composer so security advisories actually reach you.

Custom code is where these get skipped, because contributed modules have many more eyes on them than the module written for one site three years ago.

When to Handle It Yourself, and When to Bring in Help

Plenty of Drupal work does not need a specialist. Adding fields, building views, configuring displays, and installing well-documented contributed modules are all reasonable for a competent team to own.

It is worth bringing in help when:

  • A major version upgrade is due and the site carries custom modules nobody currently on the team wrote.
  • Performance problems persist after caching and hosting have been tuned, which usually means the cause is in the code.
  • An integration touches money, personal data, or anything with a compliance obligation.
  • The same bug keeps returning in different forms — a sign the problem is architectural rather than local.
  • A code review is needed before a launch, and the people who would review it are the people who wrote it.

The pattern worth avoiding is waiting until an upgrade has already failed. Understanding a codebase under pressure is considerably more expensive than reviewing it calmly beforehand.

How I Approach a Drupal Development Engagement

In my 20+ years of Drupal development, the projects that go well share a shape.

They start by reading the existing site rather than proposing a rebuild — what is configuration, what is custom, what is contributed and how far behind it is, and where the previous team took shortcuts and why. Most of what looks irrational in an inherited codebase turns out to have had a reason.

Work then goes in smallest-risk-first order, so the site stays deployable throughout rather than entering a long period where nothing can ship. And the result is written down: what was changed, what was deliberately left alone, and what debt remains. A handover that exists only in someone's memory is not a handover.

Examples of this work are on the portfolio, and the Drupal developer page covers the broader engineering side.

Next Steps

If you are working through this yourself, the highest-value starting point is an inventory: list every custom module, note which ones nobody currently understands, and check how far behind your contributed modules are. That list is usually the whole upgrade plan in outline.

If you would rather have someone else do that work, there are three ways to start:

  • A code review — a fixed-scope look at your custom modules with a written report of what will break at the next major upgrade.
  • A defined piece of development — a specific module, integration, or upgrade with an agreed scope.
  • Ongoing development support — a standing arrangement for teams that need Drupal expertise without a full-time hire.

You can request a quote with a description of your site and what you are trying to achieve, or get in touch if you would rather talk it through first. Either way, it helps to know your current Drupal version, roughly how many custom modules you carry, and what is prompting the work.

Drupal Developer
Slide 1 of 26
Acquia Purge Varnish - API V2 (Drupal Module)
Slide 2 of 26
Amun - W3CSS Sub-Theme (Drupal Theme)
Slide 3 of 26
Amunet - W3CSS Sub-Theme (Drupal Theme)
Slide 4 of 26
Anhur - W3CSS Sub-Theme (Drupal Theme)
Slide 5 of 26
Cloudflare Purge (Drupal Module)
Slide 6 of 26
Module Matrix (Drupal Module)
Slide 7 of 26
Paragraphs Bundles (Drupal Module)
Slide 8 of 26
Paragraphs Bundles Import (Drupal Module)
Slide 9 of 26
Reference Blocked Users (Drupal Module)
Slide 10 of 26
Selectify (Drupal Module)
Slide 11 of 26
Solo (Drupal Theme)
Slide 12 of 26
Solo Copy Blocks (Drupal Module)
Slide 13 of 26
Solo Utilities (Drupal Module)
Slide 14 of 26
Utilikit (Drupal Module)
Slide 15 of 26
Views 3D Carousel (Drupal Module)
Slide 16 of 26
Views 3D FlipBox (Drupal Module)
Slide 17 of 26
Views Accordion (Drupal Module)
Slide 18 of 26
Views Carousel (Drupal Module)
Slide 19 of 26
Views Hero (Drupal Module)
Slide 20 of 26
Views Lightbox (Drupal Module)
Slide 21 of 26
Views Parallax (Drupal Module)
Slide 22 of 26
Views Reveal (Drupal Module)
Slide 23 of 26
Views Slideshow (Drupal Module)
Slide 24 of 26
Views Tabs (Drupal Module)
Slide 25 of 26
W3CSS Paragraphs (Drupal Module)
Slide 26 of 26
W3CSS Theme (Drupal Theme)
1 of 26

Our mission is to make Drupal more accessible and user-friendly, empowering businesses of all sizes, especially small enterprises with powerful tools that streamline content customization and enhance digital experiences.

Need help with your Drupal project? Hire Me through Flash Web Center, LLC.

Search

Drupal Development Services: Custom Modules, Entity API, and Code That Lasts

Drupal, Cloudflare Purge, and Long Cache TTLs: How They Work Together

Drupal Blocks vs Block Content: Why Your Paragraphs Are Duplicating and How to Fix It

Transform Drupal forms with Selectify - a powerful module offering 5 custom select widgets

Paragraphs Bundles

Drupal Module - Paragraphs Bundles

Drupal Theme - Solo

Drupal Theme - Solo

Drupal Work List - Drupal Work

Reference Blocked Users (Drupal Module)

Views Carousel (Drupal Module)

Paragraphs Bundles Import (Drupal Module)

Views Tabs (Drupal Module)

W3CSS Theme (Drupal Theme)

Drupal Theme - W3CSS Theme

Drupal Theme - W3CSS Theme

Drupal Module - W3CSS Paragraphs

Drupal Module - W3CSS Paragraphs

Inspiration

Inspiration is the fuel that powers our creative engine, often coming from our surroundings, experiences, or the works of others. It's that magical moment when something clicks inside your brain, and you suddenly see a path forward that you hadn't noticed before. Inspiration can strike at any time, providing the motivation and energy needed to explore new possibilities and bring your ideas to life.

Unique Ideas

Unique Ideas

Unique ideas are the seeds of innovation, representing original thoughts or concepts that stand out from the usual. They're the sparks that ignite the process of creating something new and different, often leading to unexpected and groundbreaking solutions or products. Whether in art, science, business, or technology, unique ideas challenge the status quo and pave the way for progress.

Brainstorming

Brainstorming

Brainstorming is a creative group activity designed to generate a large number of ideas or solutions to a problem. It's a free-flowing and open-ended discussion where every suggestion is welcomed and considered, no matter how outlandish it may seem. Brainstorming encourages thinking outside the box, fostering an environment where creativity and collaboration lead to innovative solutions.

Planning

Planning

Planning is the blueprint for turning your ideas into reality. It involves setting goals, outlining steps, and organizing resources in a way that makes achieving your objectives possible. Good planning considers potential challenges and opportunities, making it easier to navigate the journey from concept to completion. It's about preparing the groundwork so that your projects can grow and flourish.

Drupal Developer

A Drupal Developer stands as the technical powerhouse behind dynamic websites, wielding expertise in PHP, custom module development, and Drupal's sophisticated API ecosystem. This role transforms business requirements into functional, secure, and scalable web solutions that power everything from small business sites to enterprise platforms serving millions of users. A Drupal Developer's expertise spans the entire development lifecycle—from architecting custom modules and integrating third-party services to optimizing performance and ensuring security compliance. Discover the complete guide to Drupal Developer skills, career paths, and hiring strategies.

Drupal Themer

A Drupal Themer serves as the artistic craftsperson who transforms wireframes and design mockups into pixel-perfect, accessible, and responsive user experiences using Twig templates, CSS, and JavaScript. This specialized role bridges the gap between design vision and technical implementation, ensuring every website not only looks exceptional but performs flawlessly across all devices and meets WCAG accessibility standards. A Drupal Themer's work encompasses the entire front-end ecosystem—from creating custom theme architectures and optimizing Core Web Vitals to implementing complex responsive designs and ensuring seamless integration with Drupal's rendering system. Explore the comprehensive guide to Drupal Themer expertise, theming best practices, and career advancement.

Drupal Architect

A Drupal Architect emerges as the strategic visionary of web construction, armed with encyclopedic knowledge of enterprise architecture patterns, infrastructure design, and Drupal's extensive technological ecosystem. This senior role operates at the highest technical level, making critical decisions that determine whether complex implementations scale successfully or collapse under real-world demands. A Drupal Architect's responsibilities begin long before development starts—during strategic planning phases where the foundation for secure, performant, and maintainable systems is established through careful evaluation of technology stacks, integration strategies, and scalability requirements. Learn about Drupal Architect skills, enterprise architecture strategies, and career progression to principal roles.

Footer menu

  • Contact
  • Professional Resume
  • Resume Summary
  • Technical Skills
  • Privacy Policy
  • Terms & Conditions
  • Search
  • Login
  • Sitemap

Copyright © 2026 Flash Web Center, LLC - All rights reserved

Developed & Designed by Alaa Haddad