Picture a restaurant kitchen during a dinner rush: orders come in faster than any one cook can plate them, so they go on a ticket rail instead — first in, first out, worked through steadily in the background while the front of house keeps taking new orders. Drupal's Queue API is that ticket rail for your module. Instead of doing slow or bulk work the instant a request comes in (sending 500 emails, resizing a batch of images, calling a slow external API), you drop each unit of work onto a queue and let something else — usually cron — work through it steadily, without ever making a visitor wait.
What you'll learn in this lesson
- Why you'd reach for a queue instead of just doing the work immediately
- How to get a queue object with the
queueservice and create it createItem()— adding a unit of work to the queue- Why queue items should be small, serializable data, not live objects
Getting a queue and adding to it
Every queue in Drupal is obtained through the queue service — a factory that hands you a queue object by name, creating the backing storage the first time it's needed:
/**
* @var \Drupal\Core\Queue\QueueFactory $queue_factory
*/
$queue = $queue_factory->get('my_module_queue_name');
// Safe to call even if the queue already exists.
$queue->createQueue();
$queue->createItem('Queue item');
$count = $queue->numberOfItems();
This is the real shape used by the Examples module's own queue_example, injected via the container in a form's create() method:
public static function create(ContainerInterface $container) {
$form = new static(
$container->get('queue'),
$container->get('database'),
$container->get('cron'),
$container->get('settings')
);
return $form;
}
createQueue() is deliberately safe to call repeatedly — Drupal's default database-backed queue implementation only actually creates the underlying table the first time an item is added, so calling it defensively before every operation (as the real example does) costs nothing and saves you from ever hitting a missing-table error.
createItem() — what actually goes on the queue
$queue->createItem($form_state->getValue('string_to_add'));
Whatever you pass to createItem() gets serialized and stored — a string, an array, a simple stdClass object. This is the detail that trips people up first: don't queue a live service, a database connection, or a loaded entity object. Queue the minimum data needed to redo the work later — an entity ID to reload, not the entity itself; a file path, not an open file handle. Whatever you serialize now has to still make sense whenever a worker eventually unserializes it, possibly minutes or hours later, in a completely fresh request.
Quick check: your module needs to notify 10,000 users by email after a bulk import. Should you loop through all 10,000 and call the mail service directly in the import's submit handler? If you said no — queue each notification as a small item (just the user ID and message) and let cron work through them — you've got the core idea: the request that triggers the work should return fast, and the actual work happens afterward, off the critical path.
Key takeaways
- The
queueservice'sget($name)method returns a queue object for a given name, creating the backing storage on first use. createItem($data)serializes and stores whatever you pass — keep it small and self-contained, never a live object or connection.createQueue()is safe to call defensively before every operation; it's a no-op if the queue already exists.- Queue order is not guaranteed across all possible backends — never rely on strict processing order for correctness.
Coming up next
You've queued the work — next you'll look at the mechanics of adding items in more realistic scenarios (bulk inserts, conditional queuing) before moving on to the piece that actually processes a queue: the QueueWorker plugin.