Queues

Flexible, reliable messaging for modern applications

Send and receive messages with asynchronous delivery from every location across Cloudflare's global network.

Guaranteed delivery

‘At least once’ delivery helps you balance message retention and end-to-end latency.

Improved visibility

See metrics on queue backlogs, consumer concurrency, and message operations.

Cost efficiency

Move messages and data around or outside your environment with no egress fees.

Background Pattern
Queues

Built for agents and high-performance apps

Simplify message processing and data movement across a variety of use cases.

View docs

Process customer messages

Send, list, and acknowledge messages across multiple queues.

Simplify LLM calling

Batch requests in order to reduce inference costs.

Protect downstream APIs

Queues can enforce rate limiting rules in order to preserve system availability.

How it all fits together

Agents on your laptop, Workers in the cloud, databases in your VPC. All addressed by private IP, all routed through one network.

Background Pattern
// Producer Worker - Send messages to queueexport default {  async fetch(request, env) {    const { searchParams } = new URL(request.url);    const message = searchParams.get('message');
    if (!message) {      return new Response('Missing message parameter', { status: 400 });    }
    // Send message to queue    await env.MY_QUEUE.send({      message: message,      timestamp: new Date().toISOString(),      userId: request.headers.get('X-User-ID'),    });
    return new Response('Message sent to queue', { status: 200 });  },};
// Consumer Worker - Process messages from queueexport default {  async queue(batch, env, ctx) {    for (const message of batch.messages) {      try {        // Process the message        console.log('Processing message:', message.body);
        // Simulate some work        await new Promise((resolve) => setTimeout(resolve, 1000));
        // Acknowledge the message        message.ack();      } catch (error) {        console.error('Failed to process message:', error);        message.retry();      }    }  },};
// Data ingestion workerexport default {  async fetch(request, env) {    const data = await request.json();
    // Send data to ETL queue for processing    await env.ETL_QUEUE.send({      type: 'data_ingestion',      payload: data,      timestamp: new Date().toISOString(),      source: 'api',    });
    return new Response('Data queued for processing', { status: 200 });  },};
// ETL processing workerexport default {  async queue(batch, env, ctx) {    for (const message of batch.messages) {      try {        const { type, payload } = message.body;
        if (type === 'data_ingestion') {          // Transform the data          const transformedData = await transformData(payload);
          // Store in data warehouse          await env.DATA_WAREHOUSE.prepare(            'INSERT INTO processed_data (data, processed_at) VALUES (?, ?)',          )            .bind(JSON.stringify(transformedData), new Date().toISOString())            .run();        }
        message.ack();      } catch (error) {        console.error('ETL processing failed:', error);        message.retry();      }    }  },};
async function transformData(data) {  // Your data transformation logic here  return {    ...data,    processed: true,    transformedAt: new Date().toISOString(),  };}
// URL discovery workerexport default {  async fetch(request, env) {    const { searchParams } = new URL(request.url);    const startUrl = searchParams.get('url');
    if (!startUrl) {      return new Response('Missing URL parameter', { status: 400 });    }
    // Add initial URL to crawl queue    await env.CRAWL_QUEUE.send({      url: startUrl,      depth: 0,      maxDepth: 3,    });
    return new Response('Crawling started', { status: 200 });  },};
// Crawler workerexport default {  async queue(batch, env, ctx) {    for (const message of batch.messages) {      try {        const { url, depth, maxDepth } = message.body;
        // Fetch the page        const response = await fetch(url);        const html = await response.text();
        // Extract links        const links = extractLinks(html, url);
        // Process the page content        await processPage(url, html);
        // Add new links to queue if within depth limit        if (depth < maxDepth) {          for (const link of links) {            await env.CRAWL_QUEUE.send({              url: link,              depth: depth + 1,              maxDepth: maxDepth,            });          }        }
        message.ack();      } catch (error) {        console.error('Crawling failed:', error);        message.retry();      }    }  },};
function extractLinks(html, baseUrl) {  // Simple link extraction logic  const linkRegex = /<a[^>]+href=["']([^"']+)["'][^>]*>/gi;  const links = [];  let match;
  while ((match = linkRegex.exec(html)) !== null) {    const href = match[1];    const absoluteUrl = new URL(href, baseUrl).toString();    links.push(absoluteUrl);  }
  return links;}
async function processPage(url, html) {  // Your page processing logic here  console.log(`Processed page: ${url}`);}

Queues Pricing

Reliable message processing. View Storage & Data pricing details

Standard Operations

Free

10,000 operations/day included

Paid

$0.40 / million operations

SiteGPT

"

We use Cloudflare for everything – storage, cache, queues, and most importantly for training data and deploying the app on the edge, so I can ensure the product is reliable and fast. It's also been the most affordable option, with competitors costing more for a single day's worth of requests than Cloudflare costs in a month. "

Bhanu Teja Pachipulusu
Bhanu Teja Pachipulusu Founder

Powerful primitives, seamlessly integrated

Built on systems powering 20% of the Internet, Queues run on the same infrastructure Cloudflare uses to build Cloudflare. Enterprise-grade reliability, security, and performance are standard.

Build without boundaries

Join thousands of developers who've eliminated infrastructure complexity and deployed globally with Cloudflare. Start building for free — no credit card required.