06 Nov 2026

feedDrupal.org aggregator

The Drop Times: Building Drupal Canvas Code Components with React and Tailwind CSS

An interactive pricing calculator demonstrates how front-end developers can build a component locally and give Drupal editors control over its settings.

06 Nov 2026 4:37pm GMT

The Drop Times: Drupal Cuts Minor-Release Security Support to Eight Months Amid Funding Strain

Organizations staying on a previous Drupal minor release will have roughly two months after its successor arrives before security coverage ends. The tighter window comes as maintainers confront rising vulnerability reports and shrinking release-management funding.

06 Nov 2026 3:32pm GMT

Fons Vandamme: Owning up to your mistakes: my broken launch email

Owning up to my mistakes

I just sent out the Webhaven launch email and every link in it was broken.

The image that I carefully created didn't load, the "Get Webhaven" call to action button went nowhere. A disaster.

To make it even worste all the links were pointing to localhost. This is meme material. I feel ashamed about the situation but I have to accept it and live and learn.

06 Nov 2026 10:00am GMT

05 Nov 2026

feedDrupal.org aggregator

Dynamosys Insights: Drupal’s Update Window Is Getting Shorter. Is Your Maintenance Plan Ready?

Drupal’s update window is getting shorter. Calendar graphic shows ordinary minor-release security support decreasing from 12 months to 8 months.

Being on Drupal 11 doesn't tell you how long your particular release will receive security fixes. A new support policy gives website teams less time to move between minor versions. Here's what to check and how to make room for that work.

05 Nov 2026 7:36pm GMT

Talking Drupal: Talking Drupal #577 - Off The Cuff 14

Today we are talking about Drupal 12, Field UI and UX. We'll also cover DruBOM as our module of the week.

For show notes visit: https://www.talkingDrupal.com/577

Topics

Resources

Hosts

Nic Laflin - nLighteneddevelopment.com nicxvan John Picozzi - epam.com johnpicozzi Emma Horrell - emma-horrell

MOTW Correspondent

Martin Anderson-Clutz - mandclu.com mandclu

05 Nov 2026 7:00pm GMT

Giorgio Pagano: How do you let an AI agent read Drupal data without misreading it?

The Drupal drop passes a p95 chart through a read-only MCP gate to an AI assistant, which shows it as a dashboard.

Native Observability started as a way to look inside Drupal with a dashboard of its own: route timings, cache and slow queries, measured by the site and read by a person on an admin page. Now an AI agent reads the same data. Ask Claude Desktop "why is this page slow?" and it fetches the numbers through the Model Context Protocol, read-only.

Handing a model the numbers is not enough, though. It reads them with common sense, and on Drupal metrics common sense fails in specific places. In my first blind comparison, 4 answers out of 5 took a drop caused by the page cache for lost traffic, even with the right instructions in front of them.

Better instructions alone did not fix it. The site now computes the signals the model would get wrong, and explains the rest with a vocabulary checked sentence by sentence against the code. In the last round, with the vocabulary on, Claude reached the right conclusion in 30 answers out of 30.

What leaves the site follows a simpler rule than a list of forbidden words: route names go out, never a URL or a parameter value. This article covers the measurements, the mistakes I found along the way, the questions you can ask and what you need to connect an agent to your own site.

Read more

05 Nov 2026 6:35pm GMT

Fons Vandamme: Why AI builds better and faster on the shoulders of giants

Image of a person standing on a giant

The best code your AI writes is the code it never has to write.

When building on top of Drupal there is luckily a lot of that.

05 Nov 2026 5:13pm GMT

The Drop Times: Drupal's Role in Digital Sovereignty Beyond the CMS

Replacing a proprietary CMS does not automatically give governments control over their digital services. Five Government Summit speakers examine the responsibilities that come with adopting open source.

05 Nov 2026 2:28pm GMT

The Drop Times: What University Drupal Projects Reveal About the Limits of Vendor Independence

Universities can replace a CMS or reorganise their websites without knowing how difficult it would be to change providers again. The missing evidence lies in contracts, documentation and the cost of transferring technical responsibility.

05 Nov 2026 12:58pm GMT

joshics.in: Benchmarking Drupal: Mitigating Synchronous Database Locking in High-Concurrency Environments

Benchmarking Drupal: Mitigating Synchronous Database Locking in High-Concurrency Environments bhavinhjoshi

Drupal's architecture provides a highly refined routing and rendering ecosystem. When deployed behind caching layers like Varnish or Redis, serving read-heavy content is a solved problem. However, engineering mission-critical platforms, such as SLA-backed procurement portals, ticketing engines, or high-volume transaction systems, requires shifting the architectural focus from read-heavy delivery to high-concurrency write stability.

When utilizing Drupal for state management or complex relational entity saves during peak traffic, default synchronous mechanisms become a critical bottleneck.

The Core Culprit: Synchronous Key-Value Upserts

In a standard deployment, Drupal manages temporary data, system variables, and specific configurations through the State API. By default, this API utilizes the database-backed Key-Value store.

The architectural vulnerability lives directly inside \Drupal\Core\KeyValueStore\DatabaseStorage::doSet(), which handles the underlying database execution for the public set() method.

// core/lib/Drupal/Core/KeyValueStore/DatabaseStorage.php

protected function doSet($key, $value) {
  $this->connection->upsert($this->table)
    ->key(['collection', 'name'])
    ->fields([
      'collection' => $this->collection,
      'name' => $key,
      'value' => $this->serializer->encode($value),
    ])
    ->execute();
}

Every time \Drupal::state()->set() is called, it triggers a synchronous Upsert query. Under the hood, MySQL's InnoDB engine enforces row-level locks (via INSERT ... ON DUPLICATE KEY UPDATE mechanics) to maintain ACID compliance during these operations. Because the default architecture blocks the PHP thread until the database confirms the write, a severe queue forms at the database layer during concurrency spikes.

The Empirical Impact (Drupal 11 & 12 Architecture)

Architectural Note: Because the synchronous DatabaseStorage::set() mechanism and InnoDB locking architecture remain unchanged in the Drupal 12.x branch, this Drupal 11 benchmark serves as a 1:1 representation of Drupal 12's concurrency limitations.

To isolate and prove this behavior, we benchmarked a standard Drupal application handling a high-volume transactional endpoint.

  • Testing Tool: Apache JMeter.
  • Load Profile: 200 concurrent threads executing heavy writes simultaneously.
  • Operation: A synchronous \Drupal::state()->set() wrapped in a database transaction to simulate a complex payload save.

The MySQL process list immediately revealed the bottleneck. Multiple independent database connections stacked up in the process list, all attempting to execute the exact same query on the jmeter_lock_test row simultaneously. Because the first thread locked the row to perform its save, all subsequent threads were trapped waiting for it to release.


Figure 1: MySQL process list demonstrating severe thread queueing and InnoDB row locking.
MySQL terminal trace showing stacked queries in the updating state

This database queue directly correlates to a severe degradation in application performance. The application's throughput plummeted to just 4.6 requests per second. Threads queued relentlessly behind the locked row, pushing average application response times to a massive 33,310ms (33.3 seconds), with peak latency hitting 40,181ms.

Ultimately, the database connection pool saturated and began throwing lock wait timeout exceptions. The application buckled, resulting in a 29.99% failure rate where nearly a third of all transactions were dropped entirely.


Figure 2: Apache JMeter Summary Report demonstrating catastrophic latency and a 29.99% error rate.
JMeter Summary Report showing 33 second average latency and 29.99 percent error rate

The Enterprise Mitigation: Asynchronous Decoupling

To scale past this limitation and guarantee 99.99% uptime, the architecture must transition from synchronous database dependence to an asynchronous state model. In our high-concurrency deployments, we mitigate this bottleneck by decoupling the State API from MySQL entirely and offloading it to a highly available Redis cluster, combined with asynchronous message queuing for relational entity writes.

1. In-Memory State Offloading

By overriding the core state service in the application's services.yml, we reroute these synchronous database calls into memory. Redis handles tens of thousands of concurrent atomic operations per second without the locking overhead of a relational database.

# services.yml
services:
  # Override the default database-backed state service
  state:
    class: Drupal\redis\State\State
    arguments: ['@keyvalue', '@redis.client.factory', '@redis.settings']

2. Asynchronous Message Queueing

For mission-critical entity writes (e.g., bid submissions, order checkouts), we completely remove the write operation from the primary PHP thread. Instead, we serialize the payload and push it to a RabbitMQ broker via a custom service.

// High-Concurrency Transaction Controller
public function submitTransaction(Request $request) {
  $payload = $request->getContent();
  
  // 1. Acknowledge receipt instantly (0ms database lock)
  $this->rabbitMqService->publish('transaction_queue', $payload);
  
  // 2. Return 202 Accepted to the user immediately
  return new Response('Transaction queued successfully.', 202);
}

The Core Patch Proposal: Implementing DestructableInterface

While external infrastructure like Redis is standard for enterprise deployments, Drupal core should natively implement a Deferred Write-Behind Strategy within the State API to protect all environments out of the box.

By analyzing the production \Drupal\Core\State\State class (which extends CacheCollector), we can surgically remove the synchronous database bottleneck. Rather than executing $this->keyValueStore->set() immediately, the class should queue the updates in memory, allow the CacheCollector to handle the static request caching, and defer the actual database upsert() to the kernel termination phase using Drupal's native DestructableInterface.

// 1. Add the interface
use Drupal\Core\DestructableInterface;

class State extends CacheCollector implements StateInterface, DestructableInterface {

  // 2. Add the queue property
  protected array $deferredWrites = [];

  // 3. Update set() to queue the write rather than blocking the thread
  public function set($key, $value) {
    if (isset(self::$deprecatedState[$key])) {
      @trigger_error(self::$deprecatedState[$key]['message'], E_USER_DEPRECATED);
      $key = self::$deprecatedState[$key]['replacement'];
    }
    
    $this->registerKeySetDuringRequest($key, $value, parent::get($key));
    
    // Queue the database write instead of executing it synchronously
    $this->deferredWrites[$key] = $value;
    
    // Allow CacheCollector to manage the static request cache
    parent::set($key, $value);
    $this->persist($key);
    static::updateCache();
  }

  // 4. Update setMultiple() to follow the same queuing logic
  public function setMultiple(array $data) {
    foreach ($data as $key => $value) {
      $this->deferredWrites[$key] = $value;
      $this->registerKeySetDuringRequest($key, $value, parent::get($key));
      parent::set($key, $value);
      $this->persist($key);
    }
  }

  // 5. Execute the bulk database write after the HTTP response is sent
  public function destruct() {
    if (!empty($this->deferredWrites)) {
      $this->keyValueStore->setMultiple($this->deferredWrites);
      $this->deferredWrites = [];
    }
  }
}

Architectural Trade-off: Eventual Consistency
Moving writes to the KernelEvents::TERMINATE phase shifts the architecture from strict ACID consistency to Eventual Consistency. By removing the InnoDB row lock, concurrent writes rely on a "Last Write Wins" resolution at the end of the request lifecycle. Furthermore, if a PHP fatal error or server crash occurs before the termination phase, the in-memory state update will be lost despite the user receiving a successful HTTP response. While this trade-off is catastrophic for financial ledgers or strict relational entities, it is the exact right compromise for the State API, which primarily manages non-critical, self-correcting metadata.

By adopting this patch, Drupal core mathematically eliminates state-based database locking during the HTTP request. It consolidates multiple scattered state updates into a single, highly efficient setMultiple() bulk write executing safely in the background, yielding instant zero-lock latency for the end user.

The Bridge Mitigation: A Drop-in Custom Module

Until a write-behind strategy is adopted in core, engineering teams can patch this bottleneck today without requiring complex external infrastructure. By writing a lean custom module (deferred_state), we can decorate the core state service and implement the DestructableInterface ourselves, bypassing the relational lock entirely.

1. The Service Decoration (deferred_state.services.yml)

services:
  deferred_state.state:
    class: Drupal\deferred_state\State\DeferredState
    decorates: state
    arguments: ['@keyvalue']
    tags:
      - { name: needs_destruction }

2. The Asynchronous Class (src/State/DeferredState.php)

namespace Drupal\deferred_state\State;

use Drupal\Core\State\State;
use Drupal\Core\DestructableInterface;

class DeferredState extends State implements DestructableInterface {
  
  protected array $deferredWrites = [];

  public function set($key, $value) {
    // 1. Maintain CacheCollector request tracking
    $this->registerKeySetDuringRequest($key, $value, $this->get($key));
    
    // 2. Queue the write instead of calling $this->keyValueStore->set()
    $this->deferredWrites[$key] = $value;
    
    // 3. Update the underlying CacheCollector storage directly
    $this->storage[$key] = $value;
    $this->persist($key);
  }

  public function destruct() {
    if (!empty($this->deferredWrites)) {
      $this->keyValueStore->setMultiple($this->deferredWrites);
      $this->deferredWrites = [];
    }
  }
}

The Engineering Standard

Relying on page caching to scale a platform only masks the symptoms of read-heavy technical debt. True enterprise stability requires engineering the underlying infrastructure to absorb massive, concurrent writes without latency. By isolating the exact code block responsible for database locking and actively decoupling it via deferred termination events or asynchronous messaging, we mathematically eliminate the locking cascade and ensure the technology stack acts as a commercial asset, not a liability.

Request an Architectural Audit

Changed

Add new comment

05 Nov 2026 8:49am GMT

Tag1 Insights: Goose 0.19: Watch Your Load Test While It Runs

Tag1 Founding Partner and CEO Jeremy Andrews, introduces Goose 0.19, which adds a live browser dashboard, pass/fail thresholds that can fail a CI build, response times to the microsecond, and peak memory cut from 959 MiB to 214 MiB at 1,000 users. Its companion crate, goose-eggs 0.7, adds helpers for load testing WordPress and WooCommerce sites.

Goose 0.19, the latest release of Tag1's open source load testing tool, lets you watch a load test in your browser while it runs. Response times, errors and active users update every second, so when a site starts to slow down you see it as it happens. Alongside it, goose-eggs 0.7 adds helpers for load testing WordPress and WooCommerce sites, and Goose itself can now fail a CI build when a site gets slower, keeps every response time to the microsecond, and runs in a quarter of the memory or less.

We compared Goose against k6 and Locust, all three in the same configuration of 1,000 users over HTTPS, running on the same two cores against the same web server. Goose sent 21,400 requests a second, against 15,800 for k6 and 8,400 for Locust, using less CPU per request than either and a fraction of the memory. The full results, and how we ran each tool, are found in this blog under the heading Compared with k6 and Locust.

An overview of what's new in Goose 0.19.

Watch a Load Test in Your Browser

There's no new code to write. Any Goose 0.19 load test gets the live web dashboard once you turn on the experimental dashboard feature in Cargo.toml:

goose = { version = "^0.19", features = ["dashboard"] }

Then add --dashboard to the command line and open http://127.0.0.1:5118/. Out of the box the page is read only. To start and stop the test and add or remove users from the browser, add --dashboard-control with either an auth token or --dashboard-no-auth (fine on your own laptop, less fine on a machine you share, and Goose prints a warning whenever you use it). The dashboard listens on localhost unless you tell it otherwise.

A load test of the Drupal Umami demo site, started from the dashboard at 50 users, raised to 400 while it runs, then stopped, and the saved report opened.

A useful new addition is the heatmap. Each column is one second of response times, so you can see a slow tail grow (or a cache warm up) long before it moves the average. You can show it for all requests or pick one request, so if only the checkout page gets slow, you can focus on it.

The Goose dashboard heatmap, where each column is one second of response times.
Figure 1: The Dashboard Heatmap, One Column per Second of Response Times

Below that are tables of every scenario, every transaction and the 100 busiest requests, and an errors table that fills in as errors happen. If you run with coordinated omission mitigation on (--co-mitigation average, for example), the requests table and the headline figures switch to coordinated omission adjusted times once mitigation has recorded an event. When a run ends, the dashboard can save its report into that run's own folder, so the runs panel lists earlier runs to download and compare.

The dashboard is opt in for 0.19. We'd like it to be on by default in 1.0, so please try it out and provide feedback. In the meantime it's cheap to leave on. In our 1,000 user memory tests it added about 2 MiB of memory and no added CPU we could measure. The Goose Book's dashboard reference says how that grows with more request names and longer runs.

The whole Goose dashboard mid run against Drupal Umami with 200 users.
Figure 2: The Full Goose Dashboard Mid Run Against Drupal Umami, 200 Users

Load Testing WordPress and WooCommerce

For years Goose has had Drupal helpers in goose-eggs, its companion crate, and an example load test against Drupal's Umami demo site. WordPress runs a much bigger slice of the web (nearly 40% of websites, by W3Techs' count), so goose-eggs 0.7 adds helpers for both WordPress and WooCommerce. The WordPress side logs in and out, searches, comments, creates and updates posts through the REST API, and finds content from the sitemap. The WooCommerce side browses the shop, searches, adds to the cart through WooCommerce's Store API (keeping each user's nonce through cart and checkout, as the Store API requires), checks out, and visits My Account.

The new woocommerce example in goose-eggs uses the helpers to simulate browsing shoppers, buyers and returning customers, and its README lists what a WooCommerce shop needs to run it.

Shoppers browsing, adding to the cart and checking out, with each step's response times filling the dashboard.

Fail the CI Build When a Site Gets Slower

This one is less visual than the dashboard but is useful for day to day testing automation. Goose 0.19 adds thresholds: pass or fail rules given on the command line.

--threshold "p95<500ms" --threshold "error-rate<1%"

Rules can check any percentile, the average, the maximum, the error rate or requests per second, for the whole test or for one request (p99<2s for GET /checkout). Once all users are up and the test is holding at its target, Goose checks every rule once a second. The first rule to fail stops the test through Goose's killswitch, with a message naming the rule and what it saw. (If you'd rather run the whole test and judge it at the end, add --no-threshold-abort.)

Either way, a failed rule makes Goose return an error, so a load test whose main passes it up with ? (as every example does) exits nonzero, which is all a CI system needs to fail the build.

Two runs against the same site: one whose rules pass and exits 0, then one with a 50 ms p95 the site can't meet, which stops and exits 1.

A GitHub Actions job that runs your load test against staging on every pull request, and fails when the site gets slower, looks like this (it tests whatever staging is running, so deploy the change there first):

name: load-test
on: [pull_request, workflow_dispatch]
jobs:
  goose:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: dtolnay/rust-toolchain@stable
      - uses: Swatinem/rust-cache@v2
      - name: Run the load test with pass/fail rules
        run: |
          cargo run --release -- \
            --host "${{ vars.STAGING_URL }}" \
            --users 50 --increase-rate 10 --run-time 2m \
            --quiet --threshold "p95<500ms" --threshold "error-rate<1%" \
            --report-file report.html
      - name: Keep the report, pass or fail
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: goose-report
          path: report.html

The report is kept whether the job passes or fails, and it has a Thresholds section showing each rule, what it measured, and which one, if any, stopped the run.

Response Times to the Microsecond

Goose used to keep response times in whole milliseconds, which was fine for most websites but too coarse for very fast ones. Against a server answering in about 0.6 ms, 0.18.1 reported an average of 0.01 ms (lower than its own 1 ms minimum) and every percentile up to the 99th as 1 ms. 0.19.0 keeps every time to the microsecond (percentiles come from buckets, so they're never more than 1% off), and reports a median of 0.59 ms and a 99th percentile of 1.05 ms for the same server.

The console, HTML, Markdown and PDF reports and the dashboard show times under 10 ms to the hundredth of a millisecond. (0.19.0's JSON report still wrote its percentiles in whole milliseconds; 0.19.1 adds microsecond fields beside them.)

Goose 0.18.1 response times against a server answering in about 0.6 ms, with every percentile at 1 ms.
Figure 3: Goose 0.18.1 Response Times Against a Server Answering in About 0.6 ms, Every Percentile at 1 ms
Goose 0.19.0 response times against the same server, to the hundredth of a millisecond.
Figure 4: Goose 0.19.0 Response Times Against the Same Server, to the Hundredth of a Millisecond

A Quarter of the Memory, or Less

Every release we try to make Goose cheaper to run, but this time the difference was big enough that we wanted real numbers before saying anything. So we ran Goose 0.18.1 and 0.19.0 on the same two cores of an arm64 machine in our Kubernetes cluster, against a small Rust web server on another machine. Each test ran five times per version, 20 minutes a run at 1,000 users and 10 minutes at 5,000, with the builds taking turns one run at a time. At 1,000 users, 0.19.0 with the dashboard on took a turn as well.

With 1,000 users requesting a page as fast as they could, 0.18.1 used 959 MiB of memory and 0.19.0 used 214 MiB. With a more realistic shape (5,000 users, each waiting 1 to 3 seconds between requests) 0.18.1 used 4,480 MiB and 0.19.0 used 763 MiB.

Bar chart of peak memory at 1,000 users for Goose 0.18.1, 0.19.0, and 0.19.0 with the dashboard.
Figure 5: Peak Memory at 1,000 Users for Goose 0.18.1, 0.19.0, and 0.19.0 with the Dashboard

The biggest single piece of the old memory we could trace was TLS, even though these tests never used HTTPS. Every Goose user gets its own HTTP client (so each user keeps its own cookies and session, as a real browser would), and in 0.18.1 each of those clients had OpenSSL load and parse the system's whole certificate bundle into a store of its own. 0.19 moved to reqwest 0.13, which uses rustls, and building a client now costs a fraction of that.

CPU went down too, though less dramatically. In the 1,000 user test, 0.19.0 spent 9% less of its own CPU per request than 0.18.1, and ran 23% fewer instructions per request (at 5,000 users it was also 9% less of its own CPU, with about half the instructions). Requests per second went up about 5%, but we wouldn't lean on that one. Two builds of the same source varied by about 2% on this machine, and the kernel's network processing took more than half of those two cores.

We also left 0.19.0 running for 12 hours with the dashboard open. It sent a little over a billion requests with no failures, and Goose's count matched the web server's own count exactly. Memory went from 219 MiB at the first hour to 225 MiB at the twelfth. Goose keeps a per second history for its graphs, which explains some of that growth, and we're still looking into the rest. Requests per second, CPU per request and the 99th percentile stayed flat the whole time.

Line chart of memory over 12 hours for Goose 0.19.0 with the dashboard, against an earlier 12 hour run of 0.18.1.
Figure 6: Memory over 12 Hours, 0.19.0 with the Dashboard Against an Earlier 0.18.1 Run

Compared with k6 and Locust

All three tools sent requests with no wait between them. Locust ran FastHttpUser with two worker processes, one per core, as its docs recommend for throughput. k6 ran its constant-vus executor and, as k6's guide to running large tests recommends, discarding response bodies to save memory. Most real sites are HTTPS, so the numbers below are over HTTPS with certificates fully checked (Locust's FastHttpUser skips the check unless you turn it on, so we turned it on).

Over HTTPS, 1,000 users, 2 cores Goose 0.19.0 k6 2.3.0 Locust 2.47.0
Requests per second 21,432 15,838 8,415
CPU per request, tool and kernel 93 µs 126 µs 238 µs
Peak memory 198 MiB 1,388 MiB 919 MiB

The CPU row counts both the tool's own CPU (the user and system time charged to its processes) and the kernel's network processing for its connections (interrupt time not charged to the tool's processes), since both came out of the same two cores.

Over plain HTTP the order was the same for throughput and CPU, but Locust used a little less memory than Goose, 190 MiB against 212. Goose was higher because each of its 1,000 users builds its own HTTP client with a TLS certificate store (about 81 MiB in all) whether or not it ever speaks HTTPS. A load test that doesn't need cookies can avoid most of that cost, since set_client_builder_without_cookies gives every user one shared client.

The throughput and CPU gaps in the table may look smaller than you'd expect from a tool written in Rust. Asking for one tiny page as fast as possible puts a big share of each request's cost in the kernel's network processing, about 50 µs a request, and for Goose that was more than half of its CPU per request.

Counting only each tool's own CPU, Goose needed 41 µs per request over HTTPS, against 76 for k6 and 173 for Locust. Put another way, at 41 µs of its own CPU a request, one core is enough for Goose's own share of about 24,000 verified HTTPS requests a second. A real load test that logs in, fills carts and checks pages gives each tool more of its own work to do, so the gap in real world load tests is even wider.

Other Changes in 0.19

There's a lot more in this release than fits here, and the CHANGELOG has all of it. A few highlights:

Some of these change how existing load tests behave, so if you're coming from 0.18, read the Goose Book's Upgrading From 0.18 page first.

What's Next

Gaggles, Goose's distributed load tests (a manager process coordinating any number of workers), will be reintroduced in the 0.20 release. From there, we will focus on a stable 1.0. If you try the dashboard or thresholds, we'd love to hear how they go, good or bad, in a GitHub issue. If you're new to Goose, the Goose Book is the place to start.

05 Nov 2026 12:00am GMT

04 Nov 2026

feedDrupal.org aggregator

Droptica: Drupal and n8n integration: connect forms, content, and business systems

Bureau avec des tubes pneumatiques transparents reliant un nœud central aux postes de travail A Drupal n8n integration can send form submissions to a CRM, create Drupal drafts from approved content in other systems, and trigger downstream work after publication. Learn which modules and APIs to use and how to keep the workflows dependable.

04 Nov 2026 6:51pm GMT

The Drop Times: Inside the Drupal AI Demo: Testing the Northmoor University Site

The demo keeps publishing decisions with editors. Hands-on testing also reveals where its AI tools still fall short.

04 Nov 2026 5:26pm GMT

The Drop Times: Théodore Biadala on Building Drupack, Simplifying Drupal Hosting and What Comes Next

Drupack promises a simpler way to run and deploy Drupal, but packaging the runtime is only part of the challenge. Creator Théodore Biadala discusses automated security updates, cross-platform testing, database performance, and the work needed to make the project practical for more developers.

04 Nov 2026 1:49pm GMT

Gábor Hojtsy: A look under the hood of how Drupal CMS 2.2 recipes speak your language too

A look under the hood of how Drupal CMS 2.2 recipes speak your language too

Did you know that before Drupal CMS 2.2, if you set up Drupal CMS in German and applied a recipe, its content types, views and roles stayed in English? Recipes are a big part of how Drupal CMS delivers features, so this was a sizable hole in the multilingual experience. Until a few months ago, recipes could not even be translated on localize.drupal.org. So we did a few things to make this possible ahead of DrupalCon Rotterdam. Here are the details.

Gábor Hojtsy

04 Nov 2026 9:17am GMT

Gspikes: Manufacturing Website Design: What the Fortune 500 Ships, and Where Drupal Fits

Manufacturing website design from 53 Fortune 500 manufacturer sites and 25 Drupal builds: catalogs, dealer locators, quote paths and what they run on.

04 Nov 2026 7:00am GMT